useItemsを作る
カスタムフックは、ただの関数
前のレッスンで、取得のコードが2か所に並びました。これを1か所にまとめます。使うのは新しい仕組みではありません。名前が use で始まり、中でフックを呼ぶ関数を作るだけです。
export function useItems(category: string) {
const [items, setItems] = useState<Item[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch("/api/items?category=" + category)
.then((res) => res.json())
.then((data: Item[]) => {
setItems(data);
setLoading(false);
});
}, [category]);
return { items, loading };
}JSX を返さないので、これはコンポーネントではありません。返すのは画面ではなく state と、それを動かす仕組みです。
使う側は2行になる
function ShoesList() {
const { items, loading } = useItems("shoes");
if (loading) return <p className="loading">読み込み中</p>;
return <ul>{items.map((item) => <li key={item.id}>{item.title}</li>)}</ul>;
}12 行あった取得の手続きが消えて、画面のコードだけが残りました。トップスの一覧も useItems("tops") と書くだけです。再試行を足したくなったら、直す場所は useItems ひとつです。
state は共有されない
よくある勘違いを先に潰しておきます。useItems を2つの部品から呼んでも、items が混ざることはありません。共有されるのはコードであって、state ではありません。 呼んだ部品ごとに別の useState が作られます。中で使っている useState は、あくまで呼び出し元のコンポーネントのものです。
名前は use で始める
use で始めるのは、ただの慣習ではありません。React の開発ツールやエディタの検査は、この名前でフックかどうかを見分けています。fetchItems のような名前にすると、中でフックを呼んでいるのに誰も気付けず、ルール違反を見逃します。
演習
useItems.ts に取得のロジックを移し、App.tsx から fetch を無くします。useItems.ts は器だけ用意してあるので、中身を書いて App.tsx から呼んでください。