useItemsを作る
カスタムフックは、ただの関数
前のレッスンで、取得のコードが2か所に並びました。これを1か所にまとめます。使うのは新しい仕組みではありません。名前が use で始まり、中でフックを呼ぶ関数を作るだけです。
別の例として、表示を開閉するフックを考えます。
TypeScript (JSX)
export function useDisclosure() {
const [open, setOpen] = useState(false);
function toggle() {
setOpen((previous) => !previous);
}
return { open, toggle };
}JSX を返さないので、これはコンポーネントではありません。返すのは画面ではなく state と、それを動かす仕組みです。
使う側は2行になる
TypeScript (JSX)
const { open, toggle } = useDisclosure();
<button onClick={toggle}>{open ? "閉じる" : "開く"}</button>呼び出し側には、表示と操作のコードだけが残ります。商品一覧では、前の回の state と useEffect を useItems の中に移し、items と loading を返します。トップスの一覧も useItems("tops") と書くだけです。再試行を足したくなったら、直す場所は useItems ひとつです。
state は共有されない
よくある勘違いを先に潰しておきます。useItems を2つの部品から呼んでも、items が混ざることはありません。共有されるのはコードであって、state ではありません。 呼んだ部品ごとに別の useState が作られます。中で使っている useState は、あくまで呼び出し元のコンポーネントのものです。
名前は use で始める
use で始めるのは、ただの慣習ではありません。React の開発ツールやエディタの検査は、この名前でフックかどうかを見分けています。fetchItems のような名前にすると、中でフックを呼んでいるのに誰も気付けず、ルール違反を見逃します。
演習
useItems.ts に async/await の取得処理を移します。useEffect は async にせず、内側の async 関数で2回 await します。App.tsx の import と呼び出しは準備済みです。useItems.ts の中で state を用意し、load の取得処理と、state を返す行を書きます。