コンポーネントのみのreactフックuseEffect()クリーンアップWillUnmount?


83

私の問題を簡単に尋ねるために、このコードの結果を説明しましょう。

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

ときForExample componentマウントは、「効果」は記録されます。これはに関連していcomponentDidMount()ます。

また、名前の入力を変更すると、「効果」と「クリーンアップ」の両方がログに記録されます。逆に、の[username]2番目のパラメーターに追加したため、ユーザー名の入力を変更してもメッセージはログに記録されませんuseEffect()。これはに関連していますcomponentDidUpdate()

最後に、ForExample componentマウントを解除すると、「クリーンアップ」がログに記録されます。これはに関連していcomponentWillUnmount()ます。

我々はすべてそれを知っている。

要約すると、「クリーンアップ」は、コンポーネントが再レンダリングされるたびに呼び出されます(アンマウントを含む)

私はそれがアンマウントある一瞬だけ「クリーンアップ」ログインするには、このコンポーネントを作成したい場合は、私はちょうどの2番目のパラメータ変更する必要useEffect()のを[]

しかし、に変更[username]する[]ForExample component、fornamecomponentDidUpdate()入力は実装されなくなります。

私がやりたいのは、コンポーネントcomponentDidUpdate()が名前入力との両方をサポートするようにすることcomponentWillUnmount()です。(コンポーネントがアンマウントされている間だけ「クリーンアップ」をログに記録します)


4
あなたは2つの別々の効果を持つことができます。username2番目の引数としてその中に配列が与えられているものと、2番目の引数として空の配列が与えられているもの。
Tholle

@Tholle 2つの別々のuseEffect()メソッドを作成する必要があるということですか?
クー

1
はい、それはそれについて行く一つの方法です。
Tholle

1
@Tholle最後のuseEffect()メソッドでオーバーライドされると思いました。私が試してみます。おかげで
クー

2
すごい!どういたしまして。クリーンアップが何をすべきかによります。2つの別々の効果は悪い解決策ではありません。
Tholle

回答:


80

クリーンアップはに依存しないため、2番目の引数として空の配列が指定usernameされた別の場所にクリーンアップを配置できuseEffectます。

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

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

<div id="root"></div>


素敵できれいな例。でも気になります。変更されたナビゲーションで何らかの方法で使用効果をトリガーできますか、それともコンポーネントツリーで上に移動する必要がありますか?「クリーンアップされた」useEffectを貼り付けるだけでは、このトリガーが表示されないためです。
ファビアンボスラー

112

複数のuseEffectを使用できます

たとえば、変数がdata1の場合、コンポーネントでこれらすべてを使用できます

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );

4
最初と最後のuseEffectsの違いは何ですか、最初のuseEffectはwillmountまたはdidmountで呼び出され、最後のuseEffectは空の配列でコールバック関数を返しました。なぜですか?各useEffectのユースケースをいつどのように使用できるかを詳しく説明していただけますか?
siluveru kirankumar19年

3
@siluverukirankumarコールバックの戻り値(関数)は、destroy(アンマウントイベント)で呼び出されるものです。そのため、最後の例はHOCであり、関数をすぐに返します。2番目のパラメーターは、R​​eactがこのフックを再実行するための変更を探す場所です。空の配列の場合、1回だけ実行されます。
ジョージー

3
おかげで@Georgyは最後のuseEffectがはっきりと見えないコールバックを返しています
siluveru kirankumar19年

2
したがって、useEffectフックを作成し、それが関数を返す場合、返される関数の前のコードはcomponentDidMount ...として実行され、返される関数のコードはcomponentWillUnmountに対して呼び出されますか?少し紛らわしいので、正しく理解していることを確認してください。useEffect(()=> {//マウントで実行するコード... return()=> {//マウント解除を実行するコード}})そうですか?
米谷

私は読んでお勧めoverreacted.io/a-complete-guide-to-useeffect ライフサイクルにフックを考えることは本当に甘くはない
モト

2
function LegoComponent() {

  const [lego, setLegos] = React.useState([])

  React.useEffect(() => {
    let isSubscribed = true
    fetchLegos().then( legos=> {
      if (isSubscribed) {
        setLegos(legos)
      }
    })
    return () => isSubscribed = false
  }, []);

  return (
    <ul>
    {legos.map(lego=> <li>{lego}</li>)}
    </ul>
  )
}

上記のコードでは、fetchLegos関数はpromiseを返します。useEffectのスコープに条件を設定して、コンポーネントがアンマウントされた後にアプリが状態を設定できないようにすることで、Promiseを「キャンセル」できます。

警告:マウントされていないコンポーネントでReact状態の更新を実行することはできません。これは何もしませんが、アプリケーションのメモリリークを示しています。修正するには、useEffectクリーンアップ関数のすべてのサブスクリプションと非同期タスクをキャンセルします。


0

useEffectは独自のスコープ内で分離され、それに応じてレンダリングされます。https://reactjs.org/docs/hooks-custom.htmlからの画像

ここに画像の説明を入力してください


ソリューションへのリンクは大歓迎ですが、それがなくても回答が役立つことを確認してください。リンクの周りにコンテキストを追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解できるようにしてから、ページの最も関連性の高い部分を引用してください。ターゲットページが利用できない場合に再リンクします。リンクに過ぎない回答は削除される場合があります
БогданОпир

0

複雑な関数やメソッドをあまりにも多く作成する代わりに、イベントリスナーを作成し、手動で行うことを心配することなく、マウントとアンマウントを自動的に実行します。これが例です。

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

    //component will unmount
    return () => {
       
        window.removeEventListener("load", pageLoad);
    }

 });

この部分が完了したので、このようにpageLoad関数から必要なものを実行します。

const pageLoad = () =>{
console.log(I was mounted and unmounted automatically :D)}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.