フックのルール
フックには2つのルールしかない
自分でフックを作れるようになると、置き場所を自分で決めることになります。守るのは次の2つだけです。
- フックは関数のいちばん上の階層で呼ぶ。条件分岐、繰り返し、入れ子の関数の中では呼ばない
- フックを呼べるのは、コンポーネントか、use で始まる名前の関数の中だけ
なぜ順番が大事なのか
React は「何番目に呼ばれた useState か」で state を見分けています。名前ではなく順番です。
const [a, setA] = useState(""); // 1番目
const [b, setB] = useState(0); // 2番目ここで1番目を if で囲むと、条件が偽になった回だけ呼ばれる数が変わります。すると2番目だったものが1番目に繰り上がり、React は前の回の1番目、つまり別の state を返します。中身が入れ替わるか、Rendered fewer hooks than expected というエラーで画面ごと落ちます。
たちが悪いのは、条件がずっと真のあいだは何事も無く動いてしまうことです。数か月後に誰かが条件を変えた日に、まったく関係のない場所が壊れます。
条件はフックの中に入れる
「特定のときだけ処理したい」は、フックを囲むのではなく、フックの中で分けます。
useEffect(() => {
if (category === "") return;
fetch("/api/items?category=" + category);
}, [category]);これなら useEffect は毎回同じ回数だけ呼ばれ、実際にやることだけが変わります。早期 return も同じです。フックより上に return を置くと、その回だけ呼ばれる数が減ります。フックを全部呼び終えてから return すると覚えてください。
名前が use で始まらない関数
function itemsFetcher() の中で useState を呼んでも、動いてしまうことがあります。ただし React から見ればそれはただの関数で、ふつうの関数として2回呼ばれたり、条件の中で呼ばれたりした瞬間に壊れます。検査の道具も名前でフックを見分けているので、警告すら出ません。フックを呼ぶ関数の名前は use で始める。 これはルールです。
演習
ルールを2つとも破っているコードを、動く形のまま直します。