0
4

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 3 years have passed since last update.

useEffect を書きながら学ぶ(React Hooks 入門シリーズ 5/6)

Last updated at Posted at 2021-02-11

ロードマップ

React 16.8 で追加された機能であるReactのHooksについて書いてあります。

書きながら学ぶ React Hooks 入門シリーズとして書き下ろしました。

はじめに

Reactの組み込みフックであるとuseRefの説明をします。

useEffect とは

コンポーネントに副作用を追加するフックです。

副作用とは以下の4つです。

  • Reactから生成されたDOMの変更
  • APIとの通信
  • 非同期処理
  • console.log

副作用が分かりにくいので、もっと噛み砕いて言えば

useEffectは、コンポネントのレンダリング後か、アンマウント(コンポネントをDOMから削除)後に、なにかの処理を実行させたいときに使うといいやつ。

って覚えとけばいいと思います。

構文

useEffect(副作用, [deps])

引数の渡し方によって、副作用が実行されるタイミングは異なります。

引数の渡し方によって、副作用が実行されるタイミング...1(毎回)

これもちゃんと動作します。

useEffect(副作用)

これは毎回のレンダリング後に副作用が実行されます。

引数の渡し方によって、副作用が実行されるタイミング...2([deps]更新時)

これは、例えば カウントアプリでボタンクリック時に state (count) が更新された時、useEffect 内が実行されます。

useEffect(()=>{
  setCount((count) => count + 1)
}, [count])

引数の渡し方によって、副作用が実行されるタイミング...3(最初の1回だけ)

第1引数をからの配列にすると、コンポネントがレンダリングされた後に1回だけ実行されます。

useEffect(()=>{
  console.log('completed render')
}, [])

クリーンナップ関数

クリーンナップ関数は以下のタイミングで実行されます。

  • コンポネントのアンマウント時
  • 副作用の再実行時
useEffect(() => {
  console.log('completed render');
  const cleanup = () => {
    console.log('cleanup!');
  };
  return cleanup;
}, []);

活用例

useEffectを使って、外部APIと通信し、非同期処理をさせて表示させましょう。

4c7bb7b56416740fee452196b0261df1.gif

APIは、ダミーの顔写真付きユーザー情報をJSONで取得できるする「Random User Generator」を使います。

最初の1回だけしかレンダリングされない バージョン

4c7bb7b56416740fee452196b0261df1.gif

サンプルコード
import React, { useState, useEffect } from "react";

const fetchUser = async () => {
  const response = await fetch("https://api.randomuser.me/");
  const data = await response.json();
  const [user] = data.results;
  return user;
};

const App = () => {
  const [user, setUser] = useState({});
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchUser().then((userData) => {
      setUser(userData);
      setLoading(false);
    });
  }, []);

  return (
    <div className="App">
      {loading ? (
        <p>loading...</p>
      ) : (
        <>
          <p>
            {user.name.first} {user.name.last} from: {user.location.country}
          </p>
          <img src={user.picture.large} alt={user.name.first} />
        </>
      )}
    </div>
  );
};

export default App;

useEffectの依存配列に何か指定したバージョン

依存配列に count state を指定した場合

これは、Next Userボタンクリック時に state (count) が更新されたことをフックして、useEffect 内が再度実行されます。

abebf6d886b8fdcce50544e032408c57.gif

サンプルコード
import React, { useState, useEffect } from "react";

const fetchUser = async () => {
  const response = await fetch("https://api.randomuser.me/");
  const data = await response.json();
  const [user] = data.results;
  return user;
};

const App = () => {
  const [user, setUser] = useState({});
  const [loading, setLoading] = useState(true);
  const [count, setCount] = useState(1);

  useEffect(() => {
    fetchUser().then((userData) => {
      setUser(userData);
      setLoading(false);
    });
  }, [count]);

  const updateUser = () => setCount((currentCount) => currentCount + 1);

  return (
    <div className="App">
      {loading ? (
        <p>loading...</p>
      ) : (
        <>
          <p>Entry Number: {count}</p>
          <p>
            {user.name.first} {user.name.last} from: {user.location.country}
          </p>
          <img src={user.picture.large} alt={user.name.first} />
        </>
      )}
      <div>
        <button onClick={updateUser}>Next User</button>
      </div>
    </div>
  );
};

export default App;

useEffectの依存配列に何も指定しないバージョン

まず以下は無限ループを繰り返す危険なコードです。

下記のサンプルコードの場合、APIをリクエストして、userstateが書き換わったことをトリガーにして、またAPIをリクエストして、userstateが書き換わることを繰り返します。

サンプルコード
import React, { useState, useEffect } from "react";

const fetchUser = async () => {
  const response = await fetch("https://api.randomuser.me/");
  const data = await response.json();
  const [user] = data.results;
  return user;
};

const App = () => {
  const [user, setUser] = useState({});
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchUser().then((userData) => {
      setUser(userData);
      setLoading(false);
    });
  });

  return (
    <div className="App">
      {loading ? (
        <p>loading...</p>
      ) : (
        <>
          <p>
            {user.name.first} {user.name.last} from: {user.location.country}
          </p>
          <img src={user.picture.large} alt={user.name.first} />
        </>
      )}
    </div>
  );
};

export default App;

さいごに

useEffect にはまだまだ奥が深い部分があります。もっと詳細に書こうと思いましたが、別の機会にします。
詳しくは、以下の記事を参考にしてください。

僕もまた書きます。

今回は以上です。

参考

0
4
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
0
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?