【React】useStateはコンポーネントの上の方に書く
課題
useStateって、コンポーネントのどこに書けばいいの?
解決策
コンポーネントのトップレベルに記述する。
Todoアプリでステータスのラジオボタン用の関数とuseStateを作成したとき、最初は以下のように両者を同じ場所に記述していた。関数と使用するuseStateが近い方が見やすいと思ったからだ。
export const App = () => {
// タスク情報のState
const [todoItems, setTodoItems] = useState([]);
// タスクを追加する関数
~~
// タスクのステータスを切り替える関数
~~
// ステータスのラジオボタン 選択されたオプションを管理するState
const [selectedStatus, setSelectedStatus] = useState(ALL);
// ステータスのラジオボタン オプションを取得する関数
~~
return ()
}
でも、これはエラーの要因となる。
正しくは以下のように、コンポーネントのトップレベルにまとめて記述する。
export const App = () => {
// タスク情報のState
const [todoItems, setTodoItems] = useState([]);
// ステータスのラジオボタン 選択されたオプションを管理するState
const [selectedStatus, setSelectedStatus] = useState(ALL);
// タスクを追加する関数
~~
// タスクのステータスを切り替える関数
~~
// ステータスのラジオボタン オプションを取得する関数
~~
return ()
}
解決策の理由
なぜ、コンポーネントのトップレベルにまとめて記述すべきなのか。
以下の理由が挙げられる。
1. Reactのルールだから
React のフックルールの一部として、フックはコンポーネントのトップレベルで呼び出す必要がある。条件付きでフックを呼び出したり、ループやネストされた関数の中でフックを呼び出したりしないようにする。例えば、if文の中にuseStateを定義するとエラーがでる。
2. ひとつの場所にまとめておくほうが管理しやすいから
useStateはpropsで子コンポーネントなどに渡すことが多い。そのような理由もあって、コンポーネントのひとつの場所でまとめて記述していたほうが管理しやすい。
3. ライフサイクルの最初に実行されて欲しいから
Reactのコンポーネントには「ライフサイクル」と呼ばれる流れがある。
■マウント(Mounting)
Reactのコンポーネントが生成されて、Webページに表示されるときの状態のこと。
■更新(Updating)
コンポーネントが状態を変えたときのこと。再レンダリングに当たる。
■アンマウント(Unmounting)
コンポーネントがWebページから消えるときのこと。
これらの流れのなかで、「マウント」では、コンポーネントが以下のような順番で処理される。
function Example() {
// 1
useEffect(() => {
// 3
return () => {
// 4
}
});
// 2
return <></>;
}
useStateや関数の定義など、初期化が行われる。
ブラウザにDOM要素をレンダリング(表示)する。
useEffectの副作用を起こす。
useEffectの副作用のクリーンアップが行われる。
マウントの中で、まずは状態が初期化される。この時、useStateの状態が保持され、その後の関数やpropsに渡すなどの処理に使われる流れになるので、useStateはコンポーネントの一番最初に読み込まれた方が良い。