useEffect完全ガイド
useEffect 完全ガイドで学んだことをまとめる
実行されたCounter関数ごとにcountがある
count は特別な bind があるわけではない
code:js
function Counter() {
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
このとき、count は特別な bind が働いているのではなく、countが更新されるたびにCounterが実行されているだけ
実行されたCounter関数ごとにイベントハンドラを定義している
code:js
function Counter() {
function handleAlertClick() {
setTimeout(() => {
alert("You clicked on: " + count);
}, 3000);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
<button onClick={handleAlertClick}>アラートを表示</button>
</div>
);
}
具体例
1回Click meを押す
アラートを表示を押す
この時点でhandleAlertClickは実行され、count=1が3000ms後に表示される
ここでClick meを押してもAlertの出力には影響しない
実行されたCounter関数ごとにuseEffectを定義している
code:js
function Counter() {
useEffect(() => {
document.title = You clicked ${count} times;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
n回目のクリックごとに、useEffect_nが実行されるイメージ
code:js
// 押下されると、コンポーネント関数が呼び出される
function Counter() {
// ...
useEffect(
// n 回目の render のエフェクト関数
() => {
document.title = You clicked ${1} times;
}
);
// ...
}
つまりこのように解釈することができる
code:js
function Counter() {
// useEffect は Counter 毎に実行されるただの関数…という解釈ができる
() => {
document.title = You clicked ${1} times;
}
}
実際は DOM のレンダリング後、という条件がある
JQeruy と React の違い
JQeruy は命令的、React は宣言的
命令的: ~をする、どのような操作を行うのかを記述する
宣言的: ~である、どのような結果になるべきかを記述する
React は props と state に応じて DOM をシンクロ(同期)させる
render するときに、それが初回か、更新かは関係ない
とはいえ、これでは初回に DOM を構築し、更新時に必要な部分だけ変更を加える、という効率的な動作ができない
解決策: React に Effect を比較させる
DOM の場合は必要な個所だけ更新することが、React はできる。
では Effect は…?
code:js
function Greeting({ name }) {
useEffect(() => {
// counter が更新されようが、name は固定なのでここは再 render 時に更新される
// べきではない
document.title = 'Hello, ' + name;
});
return (
<h1 className="Greeting">
Hello, {name}
<button onClick={() => setCounter(count + 1)}>
Increment
</button>
</h1>
);
}
そこで第2引数に、どの変数と依存しているか指定する
code:js
useEffect(() => {
document.title = 'Hello, ' + name;
レンダーごとの関数を比較して、[name]が変化していたらuseEffectを実行する
code:js
// n 回目
useEffect(() => {
document.title = 'Hello, ' + name;
// n + 1 回目
useEffect(() => {
document.title = 'Hello, ' + name;
}, name) // name = 'Bob' ... お、変化してる。useEffect 実行! Effect 内に関数を入れる
code:js
function SearchResults() {
function getFetchUrl() {
}
useEffect(() => {
fetchData();
}, []); // 本来なら query が必要 記述し忘れることが多い
}
code:js
function SearchResults() {
useEffect(() => {
// Effect 内でしか使わないなら中に含めてしまう
function getFetchUrl() {
}
fetchData();
}, []); // 本来なら query が必要 記述し忘れることが多い
}
eslint-plugin-react-hooks プラグインの exhaustive-deps で lint check ができるらしい
useCallback を使い、関数も props のように変更を検知することもできる
ただし複雑化するのでおすすめしない
useEffect は React の中では低レイヤーなもので、多様するものではなくライブラリが使うようなもの
useEffect の第2引数に関数を入れると無限ループ