こんにちは。株式会社インプルの加納です。
Reactの経験が増えるにつれ、人に教える場面も増えました。色々なご質問をいただくのですが「難しく考えすぎている」ケースも多い印象です。
React はその公式ドキュメントのトップにもあるように「UIを構築するための」ライブラリです。ただUIが構築できればそれでOKで、それ以外は普通のJavaScriptです。
- React始めたばかりで、ちょっと難しいな〜と思っている方は、本稿がシンプルに考えるための助けになるかも知れません。
- Reactのご経験豊富な方には、特に役に立たない記事です。ご了承ください。
State がメインコンセプト
シンプルに「State(状態)」がReactのメインとなる部分です。それ以外はオマケと思っても最初は差し支えないでしょう。実際、Reactのトップページにも「JSXは必須ではない」と書いてあります。
コンポーネントが状態をもつ
では、そのStateとはなんでしょうか。これはコンポーネントの状態をUIに反映するためのものです。
押すと数字が書き変わるボタンがあります。
const LikeButton = () => {
const [count, setCount] = React.useState(0);
const onClick = () => setCount((count) => count + 1);
return (
<button onClick={onClick}>
{count}
</button>
);
}
Stateを更新する = 画面を更新する
重要なポイントは1つだけです。「Stateを書き換える」と「画面が書き変わる」ことです。この画面の更新を実現するために、 Stateを書き換える専用の関数が用意されます。
上記のコードで言うと `setCount` です。この関数が実行されると `LikeButton`関数が再度実行されます。ただし、 Stateの値だけは、`LikeButton`関数が再度実行されても保持されます。
重要なのでまとめます。
- setState 関数は、そのコンポーネント関数自体を再度実行する
- その際、Stateの値だけは保持される(逆にいうとその他の変数は初期化される)
LikeButton`関数が再度実行された時、countの値だけは +1されています。これによって、画面に表示される数字だけが書き変わったように見えるのです。
<button onClick={onClick}>
{count}
</button>
useEffect (副作用フック)とは
こうして考えると、Reactにおける「Effect(作用)」がなにを指すのかが明らかになります。作用とは「画面(UI)の更新」のことです。なんと言ってもReactはUIフレームワークです。そのメイン作用は画面の更新以外にあり得ません。
画面の更新時に(副作用として)コールバックを実行する
const LikeButton = () => {
const [count, setCount] = React.useState(0);
const onClick = () => setCount((count) => count + 1);
useEffect(() => {
console.log("ボタンが押されるたびに実行されます");
}, [count]);
return <button onClick={onClick}>{count}</button>;
};
上記の useEffect は 以下の場合にコールバックを実行します。
- 画面の初期表示時
- count 変数 の更新時
両方とも、「画面の更新時」です。
よくある1回だけの useEffect
const Button = () => {
useEffect(() => {
console.log("最初に1回だけ実行したいです!");
}, []);
return <button />;
};
初期表示時だけ実行する目的で、空配列に依存した `useEffect` があります。画面の更新時に1回コールバックを実行して、その後は実行されません。
よくあるミス: 全部Stateにする
初学者の方にここまで説明すると、単一のコンポーネントで管理するStateが激減します。以下のようなコンポーネントを書いてエラーになっている…React学習時の「あるある」かと思います。
const LikeButton = () => {
const [count, setCount] = React.useState(0);
const [doubledCount, setDoubledCount] = React.useState(0);
const onClick = () => setCount((count) => count + 1);
useEffect(() => {
console.log("ボタンが押されるたびに実行されます");
setDoubledCount(count * 2);
}, [count]);
return <button onClick={onClick}>{doubledCount}</button>;
};
やりたいことは、数字を2倍にして表示することです。そのために専用のStateとして `doubledCount`を用意しています。ところが本来 State は count
だけで良いわけです。doubledCountは普通の変数で十分です。
const LikeButton = () => {
const [count, setCount] = React.useState(0);
const doubledCount = count * 2;
const onClick = () => setCount((count) => count + 1);
return <button onClick={onClick}>{doubledCount}</button>;
};
useEffect も必要ありません。
setCount 関数は、`LikeButton`関数を再度実行します。 const による 変数 `doubledCount` の宣言ももちろん再度行われます。`count` はクリック数を保持していますから、ちゃんと2倍された数字が画面に表示されます。
まとめ
難しく考えなくてOK!Stateを利用することで手軽に画面を更新するためのライブラリ。
- React は ただのUIライブラリ
- Stateを更新 = 画面を更新 ← これがメインの役割
setState がコンポーネント関数を再度実行することが意識できると、Stateの量やその他のフックもかなり減ります。または、メモ化や ref を使用した最適化など、できることがグッと増えるでしょう。