45
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ちーずのフロントエンド道場Advent Calendar 2021

Day 3

【React】useEffectの基本的な使い方・活用術・注意点

Last updated at Posted at 2021-12-02

おはこんばんちは、@ちーずです。
アドベントカレンダー3日目にして、すでに毎日記事を書くことの大変さを実感してます :qiitan-cry:

本日のテーマはuseEffectです!

useEffectとは

useEffectとは、関数コンポーネントで副作用を実行するためのhookです。
...と言われてもReactにおける副作用ってなんぞ?ってなりますよね。

Reactのコンポーネントの世界において、副作用はコンポーネントのライフサイクルのことを指します。(多分)

▼ コンポーネントのライフサイクル
  (クラスコンポーネントにおけるライフサイクルメソッド名を添えて)

  • マウントされる (componentDidMount)
  • 更新される (componentDidUpdate)
  • アンマウントされる (componentWillUnmount)

書き方

// 第一引数: コールバック関数(任意でcleanup関数を返す)
// 第二引数: 配列

useEffect(() => {
  // 実行したい処理
  return () => {
    // cleanupの処理
  }
}, [input])

毎回のレンダリング後に実行

第二引数を空にすることで、レンダリング毎に実行されます。

useEffect(() => {
  // 処理
})

コンポーネントはstateやpropsなどに変更がある度にレンダリングされてしまいます。
そのため予期しないケースでuseEffectが実行されてしまう可能性があるため、第2引数を空にすることは危険です。

初回のレンダリング後に実行

第二引数をの配列の中身を空にすると、
初回のレンダリング後のみ実行されます。

useEffect(() => {
  // 処理
}, [])

指定した値に変化があった時に実行

第二引数の配列に値を設定することで、
その値に変更がある度に実行することができます。

useEffect(() => {
  // 処理
}, [value]))

第二引数は、基本的にはlint(react-hooks/exhaustive-deps)とエディタの機能に力を借りて
自動で設定すればokです!

useEffectの活用術

ステートの変更を監視して実行

いっちばん基本的な使われ方ですが、
ステートの変更を監視して処理を実行することができます。

▼ 例

useEffect(() => {
  if (count < 10) return;
  console.log('countがもう10以上やで')
}, [count]);

条件に当てはまらない、実行したくない場合は早期リターンしてあげることをおすすめします。

外側から実行条件を渡して汎用化

処理は同様だけど、処理を実行させる条件が異なるケースがあると思います。
そのような場合は、useEffectを別コンポーネントもしくはカスタムフックとして別途作成し、
条件をprops引数で渡せるようにします。

▼ よく使うpropsや`引数

  • skip: 処理をスキップするか - falseの時のみ実行させる
  • prepared: 準備ができたか - trueの時のみ実行させる
  • onMounted / onUnMount: マウント または アンマウント で実行させる

▼ 例: カスタムフックを使用した例

export const useCustomHook = (skip: false) => {
  useEffect(() => {
    if (skip) return;
    // 共通化したい処理
  }, [skip])
} 

カスタムフックとはなんぞ?と思った人にはおすすめの記事があります。(宣伝)

※ 活用術に関しては、発見次第今後追記していく予定です!

useEffectの注意事項

一見便利なuseEffectですが、使い方を誤ると予期せぬバグを産んでしまいがちです。
そのため、どのようなバグが発生しがちか、どのように対処すべきかも理解した上で使えるとより良いです。

無限ループに気をつける

useEffectは特に無限ループに陥りがちです。

ありがちなのが、ステートの更新をuseEffectの中で行っているが、
そのuseEffectはステートが更新されたら再度実行されるようになっていて、
更新 → 実行 をひたすら繰り返してしまうことです。

const [count, setCount] = useState(0)
		 
useEffect(() => {
  setCounter(prev => prev + 1)
}, [count])

useEffectは、ちゃんと無限ループがどのようなケースで発生しうるかを理解して使うことが大事です。

▼ 参考

メモリリーク対策をしっかりする

メモリリークとは、実行中のプログラムが割当てたメモリ領域を解放し忘れることで起きるバグです。

useEffectを使った場合、非同期の処理においてResponse返ってくるよりも先にコンポーネントが消失した場合に発生しうります。

その場合は、ちゃんとコンポーネントがマウントされた状態であることを判定した上で実行しましょう。

▼ 例

useEffect(() => {
  let isMounted = true;

  // promise() - Promiseを返す何かしらの処理
  promise().then((n) => {
    isMounted && setState(n);
  });

  // アンマウント時にmountedをfalseに変更
  return () => {
    isMounted = false;
  };
}

▼ 参考

イベントを追加した時は、クリーンアップ時に削除する

addEventListeneruseEffect内で使う場合、
useEffectが走る度にイベントが追加され続けてしまいます。
そのため、クリーンアップ時にイベントを一度削除するよう制御しましょう。

▼ 例

useEffect(() => {
  window.addEventListener('resize', handleResize);
  return () => window.removeEventListener('resize', handleResize);
}, [handleResize]);

以上、「useEffectの基本的な使い方と活用術」でした!
明日はuseRefの基本的な使い方と活用術に関してです!
お楽しみに:hibiscus:

45
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?