副作用
ある機能がプログラム上のデータを変化させ、それ以降の演算の結果に影響を与えること
つまり、数学的関数は本来計算結果を返すことが目的であるが、その過程で周囲の状態を変化させてしまうこと
副作用の無い関数例
code:double.ts
function double(x: number) :number {
return 2 * x;
}
参照透過性がある
同じ条件を与えれば結果は同じになる
他のいかなる機能の結果にも影響を与えない
副作用の有る関数例
code:add.ts
// グローバル変数numを参照し、それを増加させて返すもの
let num = 0;
function add(x: number): void {
num = num + x;
}
機能(関数)の外側の状態を変化させる
参照透過性が無い(同じ条件を与えても結果が同じにならない)
- 以下フロントエンドの話
レンダリングによって引き起こされる処理
useEffectは再レンダリング後に呼ばれる
第二引数に設定した値に関しては、同じ値の場合useEffect処理がスキップされる
つまり第二引数の配列に渡した値が変更されると実行される
buttonのonClickでcountの値が変わる事が副作用
副作用が生じたからuseEffect内の処理が実行される
引数以外の要因で結果が変わる関数
関数の外に影響を与える関数
「薬を飲んだら眠くなる」の意の副作用とは違う
副作用=適切な場所に配置すべき
副作用≠書くべきではない
Reactにおける副作用
なんらかの処理の結果、DOMが書き換えられ再レンダリングが生じること
副作用を起こす可能性がある処理例
DOMの変更
APIとの通信
console.log
ファイルへの書き込み
state/propsの変更
オブジェクトまたはその内部のプロパティへの代入
配列のpush()
code:reRender.tsx
const Counter: React.FC = () => {
const countUp = () => {
setCount((prev) => prev + 1);
}
const countDown = () => {
setCount((prev) => prev -1);
}
const handleToggle = () => {
setIsOpen(!isOpen);
}
// useEffect_1
useEffect(() => {
console.log("再レンダリングされるたび呼ばれる");
})
// useEffect_2
useEffect(() => {
console.log("countの値が変わるたび呼ばれる");
return (
<>
<button onClick={countUp}>+</button>
<button onClick={countDown}>-</button>
<button onClick={handleToggle}>{isOpen ? "close": "open"}</button>
<p>count: {count}</p>
</>
)
}
上のコードの場合
countの値を変更する時
+ or - ボタンの押下によりcountUp / countDown 関数を呼ぶ
count の値が変わる
再レンダリングされる
再レンダリング後にuseEffect_1が呼ばれる
log: 再レンダリングされるたび呼ばれる
レンダリング前と再レンダリング後でcountの値が異なるから、useEffect_2が呼ばれる
log: countの値が変わるたび呼ばれる
isOpenの値を変更する時
open or close ボタンの押下によりhandleToggle関数を呼ぶ
isOpenの値が変わる
再レンダリングされる
再レンダリング後にuseEffect_1が呼ばれる
log: 再レンダリングされるたび呼ばれる
レンダリング後と再レンダリング後でcountの値は同じなのでuseEffect_2はスキップされる