https://images.unsplash.com/photo-1627398242454-45a1465c2479?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb

前回までの記事

React Hooksを学ぶ【useState編】

ReactHooksを学ぶ【useReducer編】

ReactHooksを学ぶ【useRef編】

参考

useEffect – React

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

useEffectとは?

コンポーネント内のロジックは2種類ある

以下は公式ドキュメントの抜粋。

エフェクトについて説明する前に、React コンポーネント内の 2 種類のロジックについて理解しておく必要があります。

この後には、「でもこの2種類を完全に分離仕切ることは出来ないよね」、と続く。

ドキュメントの中ではReactの設計思想が、

UIはUIとして独立させてそれだけに専念

それ以外の処理はイベントハンドラとして独立

ということを強調したうえで、コンポーネントの中でイベントを扱うための方法の説明をしている。

純粋と副作用

上のドキュメントにある、「純粋」とは何なのか?それは以下の条件を満たすこと。

  1. 特定の値には特定の値を返す
  2. 関数外の状態は参照・変更しない
  3. 関数外に影響を及ぼさない
  4. 引数で渡された値を変更しない

例えばこんな。

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 に、その関数をレンダーの後(その時点なら副作用が許されます)で呼ぶように指示できます。ただしこれは最終手段であるべきです。