React useEffectでロード関数を1回だけ呼び出す方法


205

useEffectはフックがすべての変更で機能に渡され実行されます反応します。これは、必要なプロパティが変更された場合にのみ呼び出せるように最適化できます。

から初期化関数を呼び出し、componentDidMount変更時に再度呼び出さない場合はどうなりますか?エンティティをロードしたいとしますが、ロード関数はコンポーネントからのデータを必要としません。useEffectフックを使用してこれをどのように作成できますか?

class MyComponent extends React.PureComponent {
    componentDidMount() {
        loadDataOnlyOnce();
    }
    render() { ... }
}

フックを使用すると、次のようになります。

function MyComponent() {
    useEffect(() => {
        loadDataOnlyOnce(); // this will fire on every change :(
    }, [...???]);
    return (...);
}

回答:


388

useEffect最初のレンダリング後に 指定された関数のみを実行する場合は、2番目の引数として空の配列を指定できます。

function MyComponent() {
  useEffect(() => {
    loadDataOnlyOnce();
  }, []);

  return <div> {/* ... */} </div>;
}

27
または、データを取得するために使用するパラメーター(ユーザーIDなど)がある場合は、その配列でユーザーIDを渡すことができ、それが変更されると、コンポーネントがデータを再フェッチします。ユースケースの多くはそのように機能します。
trixn 2018年

4
うん...スキップについての詳細はここに文書化されている:reactjs.org/docs/...
Melounek

これは最も単純な答えのようですが、ESLintは不平を言います...このスレッドで他の答えを参照してくださいstackoverflow.com/a/56767883/1550587
Simon Hutchison

85

TL; DR

useEffect(yourCallback, []) -最初のレンダリング後にのみコールバックをトリガーします。

詳細説明

useEffectコンポーネントのすべてのレンダリング後デフォルトで実行されます(そのため、エフェクトが発生します)。

useEffectコンポーネントに配置するときは、コールバックをエフェクトとして実行することをReactに伝えます。Reactは、レンダリング後およびDOM更新の実行後にエフェクトを実行します。

コールバックのみを渡す場合-コールバックは各レンダリング後に実行されます。

2番目の引数(配列)を渡す場合、Reactは最初のレンダリングの後、配列の要素の1つが変更されるたびにコールバックを実行します。たとえば配置時useEffect(() => console.log('hello'), [someVar, someOtherVar])-コールバックは、最初のレンダリングの後、およびいずれsomeVarかまたはsomeOtherVar変更されたレンダリングの後に実行されます。

2番目の引数に空の配列を渡すことにより、Reactは配列をレンダリングするたびに比較し、何も変更されていないことを確認するため、最初のレンダリングの後でのみコールバックを呼び出します。


68

useMountEffectフック

コンポーネントのマウント後に関数を1回だけ実行することは、実装の詳細を隠す独自のフックを正当化するほど一般的なパターンです。

const useMountEffect = (fun) => useEffect(fun, [])

任意の機能コンポーネントで使用します。

function MyComponent() {
    useMountEffect(function) // function will run only once after it has mounted. 
    return <div>...</div>;
}

useMountEffectフックについて

useEffect2番目の配列引数を使用する場合、Reactはマウント(初期レンダリング)後、および配列の値が変更された後にコールバックを実行します。空の配列を渡すため、マウント後にのみ実行されます。


19
ESLintルール「react-hooks / exhaustive-deps」は常に空の依存関係リストで失敗するため、私はあなたの答えを強く望みます。たとえば、有名なcreate-react-appテンプレートはそのルールを適用します。
Dynalon

1
@Dynalonに完全に同意します。これは、ESLintルールに干渉しないため、受け入れられる解決策です
Mikado68 '12

@DynalonとMikado68に感謝します:-)。決定はOPの特権です。私はあなたのコメントについて通知を受けましたが、OPはそうではありませんでした。質問に直接コメントすることで、彼に提案できます。
Ben Carp

2
これでuseMount、エフェクト関数が小道具から何かを必要とするが、その値がlinter warnigなしで変更されても再度実行する必要がない場合に使用できます。useEffect(()=>console.log(props.val),[])依存関係の警告が欠落してuseMount(()=>console.log(props.val))いますが、警告は出されませんが「機能します」。ただし、コンカレントモードで問題が発生するかどうかはわかりません。
HMR

1
私はこれが好きです:)以前に述べたのと同じ理由。ESLintルールはこれについて不満を言うことはなく、その名前は空の配列よりも理解しやすい
Frexuz

20

空の配列を2番目の引数としてに渡しますuseEffect。これは事実上、ドキュメントを引用してReactに伝えます。

これは、エフェクトが小道具や状態の値に依存しないため、再実行する必要がないことをReactに伝えます。

これが動作することを示すために実行できるスニペットです。

function App() {
  const [user, setUser] = React.useState(null);

  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        setUser(data.results[0]);
      });
  }, []); // Pass empty array to only run once on mount.
  
  return <div>
    {user ? user.name.first : 'Loading...'}
  </div>;
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>


4

私はmount関数を定義するのが好きです。関数はEsLintをだまして同じようにだましuseMountます。

const mount = () => {
  console.log('mounted')
  // ...

  const unmount = () => {
    console.log('unmounted')
    // ...
  }
  return unmount
}
useEffect(mount, [])


0

コツは、useEffectが2番目のパラメーターを取ることです。

2番目のパラメーターは、コンポーネントが再レンダリングする前に変更されたことを確認するためにチェックする変数の配列です。チェックする小道具と状態のビットをここに置くことができます。

または、何も入れません:

import React, { useEffect } from 'react';

function App() {
  useEffect(() => {

    // Run! Like go get some data from an API.

  }, []); //Empty array as second argument

  return (
    <div>
      {/* Do something with data. */}
    </div>
  );
}

これにより、useEffectが1回だけ実行されるようになります。

ドキュメントからのメモ:

この最適化を使用する場合は、時間の経過とともに変化し、エフェクトによって使用されるコンポーネントのスコープ(propsやstateなど)からのすべての値が配列に含まれていることを確認してください。それ以外の場合、コードは以前のレンダリングの古い値を参照します。


3
CSS Tricksから文字通りコピー/貼り付けする場合、できる限り最小限にソースにクレジットを付けます。 css-tricks.com/run-useeffect-only-once
バーティッシュ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.