何をしていたか(悪いコード)
React Native で、とあるアプリで、アカウント情報を表示する画面を作成していた。
ReactNavigation を利用していた。
処理の概要は以下
export default function MyPage {
// ユーザ情報
const [user, setUser] = useState();
// ユーザ情報取得処理(あとで再利用する)
const userCheck = async () => {
const user = await getUser();
setUser(user);
}
// 画面表示開始時に一度だけ読み取る
useEffect(userCheck, []);
// ユーザ情報がなければ処理中を表示
if (!user) {
return (
<Text>処理中</Text>
);
}
// ここから本画面 画面遷移用にnavigation 確保
const navigation = useNavigation();
return (
<Text>本画面</Text>
{/* 実際は、画面遷移などをする処理がある */}
);
先に結論
useNavigation も立派な Hook なので、条件によって呼ばれたり呼ばれなかったりするとこのエラーになります。
何が起きたか
処理的には問題はないが、以下のエラーが表示されてビビる
Warning: React has detected a change in the order of Hooks called by MyPage.
This will lead to bugs and errors if not fixed.
For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useState useState
2. useState useState
3. useEffect useEffect
4. undefined useContext
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
何をしたか
ひとまずURL https://reactjs.org/link/rules-of-hooks
の記載があるので、皿の目で読む。
翻訳などを使って、以下のように理解
Hooks は、レンダリング毎に、同じ順序、同じ量、同じものを毎回呼ばれるようにしなきゃいかんよ
上を読んでもハマる。どう考えたか
- useState は毎度同じものが同じ順序で呼び出されるはず
- useEffect も useState の後に呼び出されているし、👆のURL記載事項には反していないはず
- あれ? useContext ってなんだっけ? 使ってたっけ?
結局何だったか
useNavigation がHookであることを忘れていた。
useNavigation は、内部で useContext を使っているので、この順序になっていた。
state の条件により、 useNavigation が呼ばれたり呼ばれなかったりすると、このエラーになるようだ。
良いコード
export default function MyPage {
// ユーザ情報
const [user, setUser] = useState();
// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
// 画面遷移用にnavigation 確保(条件に左右されず useNavigation は呼ばれるようにしないとエラーになるぞ)
const navigation = useNavigation();
// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
// ユーザ情報取得処理(あとで再利用する)
const userCheck = async () => {
const user = await getUser();
setUser(user);
}
// 画面表示開始時に一度だけ読み取る
useEffect(userCheck, []);
// ユーザ情報がなければ処理中を表示
if (!user) {
return (
<Text>処理中</Text>
);
}
// ここから本画面
return (
<Text>本画面</Text>
{/* 実際は、画面遷移などをする処理がある */}
);
教訓
- ライブラリをじゃんじゃん使うのはいいが、中で何をしているのか、特に Hooks については気を付けよう
- use という言葉から、Hooks だと連想できるようになろう
- 正常に動作するので、最悪放置しようと思ったけど、そんな自分にばいばいきん