
今日はアプリ開発を進めていたのですが、
ReactのHooksエラーにガッツリ沼りました。
結果的には「ちゃんとルールを理解すればシンプル」なのですが、
エラー文が分かりにくく、初心者が一番詰まりやすいポイントだと感じたので、
備忘録としてまとめます。
Contents
今日やっていたこと(ざっくり)
- Expo(React Native)環境で画面を実装
- 背景画像やテーマカラーを調整
- フォントを
expo-fontで読み込み - 状態管理に
useState,useEffect,useCallbackなどを使用
ここまでは普通だったのですが、
ある瞬間からアプリが起動しなくなりました。
出たエラー(これ)
Rendered more hooks than during the previous render.
もしくは:
React has detected a change in the order of Hooks called
スタックトレースには
- useCallback
- HomeScreen
- renderWithHooks
などが並びます。
正直、最初は意味が分かりません。
「Hooksの順序」って何?
ReactのHooksには絶対的なルールがあります。
Hooksは
毎回、同じ順番で、同じ数だけ呼ばれなければならない
Reactは内部で
「このコンポーネントは
1番目に useState
2番目に useEffect
3番目に useCallback
…」
という 順序表 を持っています。
これが1つでもズレると、即クラッシュします。
今回の原因(ほぼ100%これ)
const [fontsLoaded] = useFonts(...);
if (!fontsLoaded) {
return null;
}
const memo = useMemo(() => {...}, []);
一見、問題なさそうですが これがアウト。
何が起きているか?
- 初回レンダリング
→fontsLoaded === false
→return nullで 途中終了 - 次のレンダリング
→fontsLoaded === true
→useMemoまで実行される
つまり、
前回:Hook 3個
次回:Hook 4個
React「いや順序変わっとるやん、無理」
→ エラー発生
正しい書き方(超重要)
❌ ダメな例
useFonts();
if (!fontsLoaded) return null;
useEffect(...);
✅ 正しい例
useFonts();
useEffect(...);
if (!fontsLoaded) return null;
Hookは必ず「return より前」に全部置く
これだけです。
useCallback + useFocusEffect も注意
こんなコードもOKです:
useFocusEffect(
useCallback(() => {
// 処理
}, [])
);
でも、
if (condition) {
useCallback(...)
}
これは 即アウト。
条件分岐は
Hookの中でやる
が鉄則です。
それでも直らない場合(罠)
Hookの順序を直しても、
ExpoのFast Refreshが古い状態を保持していることがあります。
この場合、正しいコードでもエラーが出続けます。
必ず一度これを実行
npx expo start -c
(キャッシュ完全クリア)
これで直ることがかなり多いです。
今日の学びまとめ
- Hooksは「条件付きで呼ばない」
return nullは 全Hooksの後- エラー文より「何回目のレンダーか」を考える
- Fast Refreshは時々ウソをつく
正直な感想
今日はほぼ
「エラーを読む → 仮説 → 直す → まだ出る」
を繰り返して終わりました。
でも、
- Reactがどう状態を管理しているか
- Hooksがなぜ制約だらけなのか
は、かなり腹落ちしました。
こういう地味な理解が、
あとで 「ハマらない力」になるんだと思います。









