Open5

個人開発メモ_Slangy

YujiYuji

ToggleSwitchButtonの実装

参考

https://tsukulog.net/2021/05/20/react-on-off/

input(type="checkbox")要素に指定できるCSSプロパティはheightやwidth、marginといったものだけ
上記の問題を解決するために、label要素を使用して、装飾する

label要素について

  • label要素のfor属性とinput(type="checkbox")要素のid属性の値を一緒にして紐づかせることができる
  • これにより、label要素のクリック=input(type="checkbox")要素のチェックとなる
  • label要素は、どんなCSSプロパティも指定できる
type ToggleSwitchButtonProps = {
  on: boolean;
  toggle: () => void;
};

const ToggleSwitchButton = ({ on, toggle }: ToggleSwitchButtonProps) => {
  return (
    <>
      <input
        type="checkbox"
        name="toggle"
        id="toggle"
        className="hidden"
        checked={on}
        onChange={toggle}
      />
      <label
        htmlFor="toggle"
        className={`box-content overflow-hidden border block h-6 rounded-full cursor-pointer ${
          on ? "bg-blue-400" : "bg-gray-100"
        }`}
      >
        <span
          className={`absolute block w-6 h-6 bg-white rounded-full shadow transition-transform transform ${
            on ? "translate-x-6" : ""
          }`}
        ></span>
      </label>
    </>
  );
};

export default ToggleSwitchButton;

YujiYuji

モバイル用のnavスライドを実装

要件

  • ハンバーガーメニューをクリックすると、navスライドが右側から出てくる
  • ×ボタンをクリックで閉じる
  • navスライドの外側をクリックで閉じる
  • リンクをクリックで閉じる
  • スライドが表示されている場合は、外側の背景を暗くし、スクロールできないようにする。

スライドが表示されている場合は、外側の背景を暗くし、スクロールできないようにする。

Bodyのスタイルを変更:
メニューが開いているときに、bodyにoverflow-hiddenクラスを追加します。これにより、ページ全体のスクロールが無効になります。

オーバーレイを追加:
メニューが開いている間に、背景に半透明のオーバーレイを追加して、メニュー以外のコンテンツとの間に明確な境界を作ります。このオーバーレイをクリックすることで、メニューを閉じることができるようにします。

import React, { useState } from 'react';

const MobileNav = () => {
  const [isOpen, setIsOpen] = useState(false);

  const toggleMenu = () => {
    setIsOpen(!isOpen);

    if (isOpen) {
      document.body.classList.remove('overflow-hidden');
    } else {
      document.body.classList.add('overflow-hidden');
    }
  };

  return (
    <div className="relative">
      {/* トリガーボタン */}
      <button
        onClick={toggleMenu}
        className="p-4 focus:outline-none"
      >
        {isOpen ? 'Close' : 'Menu'}
      </button>

      {/* ナビゲーション */}
      <div
        className={`fixed top-0 right-0 w-64 h-full bg-gray-200 transform transition-transform ease-in-out ${
          isOpen ? 'translate-x-0' : 'translate-x-full'
        }`}
      >
        {/* ... */}
      </div>

      {/* オーバーレイ */}
      {isOpen && (
        <div
          className="fixed top-0 left-0 w-full h-full bg-black opacity-50 z-10"
          onClick={toggleMenu}
        ></div>
      )}
    </div>
  );
}

export default MobileNav;

なぜ、bodyにoverflow-hiddenをつけるとスクロールできなくなる?

overflow-hiddenは、要素からはみ出たものは非表示にするプロパティ。
よってbody要素に指定した場合は、bodyからはみ出すものは非表示になる = スクロール機能がなくなる。

【GPTの解答】
overflow-hiddenは、要素の中身がその枠を超えても表示されないようにするCSSプロパティです。
bodyタグにこのプロパティを適用すると、ページ全体の内容がブラウザのビューポートを超える場合でも、
それを超えた部分は表示されず、スクロールもできなくなります。これにより、
ページのスクロールが一時的に禁止される効果が得られます。

外側のチェックボックスなどがクリックできてしまう

body要素に、pointer-events-noneを付与し、navスライドの箇所にpointer-events-autoを付与する。

YujiYuji

ローカルストレージについて

ローカルストレージは、Webブラウザに組み込まれたキーと値のペアのデータを永続的に保存するためのWebストレージの一部。Webページのセッション間でデータを保存するためのツールとして用いられる。
簡単なデータの永続的な保存をブラウザレベルで行うためのツールとして非常に役立つが、その使用には適切なケースと注意が必要

主な特徴:

永続的: データはブラウザを閉じても消えず、手動で削除しない限り保存され続けます。
容量: 通常、ブラウザあたり約5MBのデータを保存することができます。
ドメイン固有: データは、それをセットした同じオリジン(プロトコル、ドメイン、ポート)からのみアクセス可能です。
文字列のみ: ローカルストレージは文字列のみを保存できるため、オブジェクトや配列を保存する際はJSON形式に変換する必要があります。

使用方法:

データの追加/更新:

localStorage.setItem('key', 'value');

データの取得:

const value = localStorage.getItem('key');

データの削除:

localStorage.removeItem('key');

全データの削除:

localStorage.clear();

制限と注意点:

データは全て文字列として保存されるので、数値やオブジェクトを保存する際は適切に変換する必要がある。
サーバーサイドでのアクセスは不可能。
セキュリティ上のリスク: 機密情報やパーソナルな情報をローカルストレージに保存することは推奨されません。
同一オリジンポリシーにより、異なるオリジンからのデータへのアクセスは制限される。

YujiYuji

Reactのリファクタリング

https://hello.shelfy.co.jp/960cf4736e4d4a6a87161c34bac17fac

propsとchildrenを適切に使い分け

子Componentが親Componentに依存しているのであればpropsを使う
依存していないのであればchildrenを使う

全体感の見えるComponent設計

Componentを単一責任に分けるのは大切という前提の上で、不必要にComponentを分けてネストさせるのではなく、Componentファイルを見た時の全体感の掴みやすさも重要視

その他

  • ESlintのルールの選定が参考になる
YujiYuji

カスタムフックの返り値は、配列 OR オブジェクト?

参考記事

https://blog.ojisan.io/why-hooks-need-array/

  • 配列で返すと、使う側で名前を自由に変えれるが、オブジェクトだとhooks の呼び出し後に名前を付け直す必要がある。
  • custom hooks の開発者はその hooks が汎用的に使われ文脈にそった名前を与えられる使われ方をするかどうかを考えて、オブジェクトで返すか配列で返すかをすれば良い
  • 配列で返すとオブジェクトのように key で自由に取り出しができないが、_などの placeholder を用意してピンポイントで必要な要素を取り出せる。
  • 結論:hooks 関数から戻り値を配列で返すと、 hooks の呼び出し時に束縛する変数名を自由に変えられ、可読性を上げられる。

GPTに聞いてみた

カスタムフックの返り値を配列にするか、オブジェクトにするかは設計の選択です。どちらが「正しい」とは断定できませんが、それぞれのアプローチのメリットとデメリットを以下に示します。

配列を返す場合:

メリット:
順序に依存した命名:フックを使用する側で返り値の変数名を自由に命名できるため、状況や文脈に合わせて適切な名前を選ぶことができます。

const [value, setValue] = useCustomHook();

簡潔性:返り値を分解代入する際に短く書ける。

デメリット:
順序の重要性:返す順序が重要であり、変更するとバグが発生する可能性があります。
明確さの欠如:返り値の構造や目的が直感的にわかりにくい場合がある。

オブジェクトを返す場合:

メリット:
名前による参照:返り値が明示的になり、フックの内部の構造や意図がわかりやすくなる。

const { value, setValue } = useCustomHook();

順序に依存しない:オブジェクトのプロパティには順序がないため、順序の変更によるバグのリスクがありません。

拡張性:返り値を拡張する場合、新しいプロパティを追加するだけでよく、使用側のコードを変更する必要が少ない。

デメリット:
冗長性:多少の記述量が増える場合がある。
命名の制約:フックが返すオブジェクトのキーの名前に依存するため、使用する側での命名の自由度が低くなる。

結論として、カスタムフックの目的や使用するコンテキストに応じて、返り値の形式を選択することが推奨されます。予期される使用方法や拡張のニーズ、チームのコーディング規約や好みも、この選択を導く要因となり得ます。

配列で返した場合、呼び出し元で、型エラーが発生する

解決法:
カスタムフック側の返り値の型を明記してあげる。