https://ja.react.dev/learn/synchronizing-with-effects
https://zenn.dev/fujiyama/articles/c26acc641c4e30
https://zenn.dev/uhyo/articles/useeffect-taught-by-extremist
https://kinsta.com/jp/knowledgebase/react-useeffect/
https://qiita.com/keiya01/items/fc5c725fed1ec53c24c5
以下は公式ドキュメントの抜粋。
エフェクトについて説明する前に、React コンポーネント内の 2 種類のロジックについて理解しておく必要があります。
- レンダーコード(UI の記述で説明)とは、コンポーネントのトップレベルにあるものです。ここは、props や state を受け取り、それらを変換し、画面に表示したい JSX を返す場所です。レンダーコードは純粋でなければなりません。数学の式のように結果を計算するだけで、他のことは行わないようにする必要があります。
- イベントハンドラ(インタラクティビティの追加で説明)とは、コンポーネント内にネストされた関数であり、計算だけでなく何かを実行するものです。イベントハンドラは、入力フィールドを更新したり、商品を購入するための HTTP POST リクエストを送信したり、ユーザを別の画面に遷移させたりすることができます。イベントハンドラには、特定のユーザアクション(例えば、ボタンクリックや入力)によって引き起こされてプログラムの状態を変更する、“副作用 (side effect)” が含まれています。
この後には、「でもこの2種類を完全に分離仕切ることは出来ないよね」、と続く。
ドキュメントの中ではReactの設計思想が、
UIはUIとして独立させてそれだけに専念
それ以外の処理はイベントハンドラとして独立
ということを強調したうえで、コンポーネントの中でイベントを扱うための方法の説明をしている。
上のドキュメントにある、「純粋」とは何なのか?それは以下の条件を満たすこと。
例えばこんな。
interface testprops{
value:number
};
const Effect = ({value}:testprops) => {
const double = (value:number) => {
return value * 2;
}
return (
<>
<div>{double(value)}</div>
</>
)
};
export default Effect;
value=2を指定すれば絶対に4が返ってくるし、3を指定すれば6が返ってくる。
そして、上記を守っていないものは、「副作用」と呼ばれる。以下は公式ドキュメントより。
import { useState, useRef, useEffect } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
//副作用
if (isPlaying) {
ref.current.play(); // Calling these while rendering isn't allowed.
} else {
ref.current.pause(); // Also, this crashes.
}
return <video ref={ref} src={src} loop playsInline />;
}
export default function App() {
const [isPlaying, setIsPlaying] = useState(false);
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer
isPlaying={isPlaying}
src="<https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4>"
/>
</>
);
}
これは外部で指定された動画をVideoPlayerコンポーネントの中で制御をしようというものであり、明確な副作用を有している。
そして、この副作用は何なのかというと、上で少し言及した「イベントハンドラ」に他ならない。というのはちょっと言い過ぎで、イベントハンドラの一部が副作用を持つといったほうがきっと正しい言い方だろう。実際に公式ドキュメントにも以下のように書かれている。
React では、副作用は通常、イベントハンドラの中に属します。イベントハンドラは、ボタンがクリックされたといった何らかのアクションが実行されたときに React が実行する関数です。イベントハンドラは、コンポーネントの「内側」で定義されているものではありますが、レンダーの「最中」に実行されるわけではありません! つまり、イベントハンドラは純粋である必要はありません。
いろいろ探してもあなたの副作用を書くのに適切なイベントハンドラがどうしても見つからない場合は、コンポーネントから返された JSX に
useEffect
呼び出しを付加することで副作用を付随させることも可能です。これにより React に、その関数をレンダーの後(その時点なら副作用が許されます)で呼ぶように指示できます。ただしこれは最終手段であるべきです。