web-dev-qa-db-ja.com

配列依存関係でuseEffectフックを適切に使用する方法。 reduxストアから状態を渡しましたが、それでもコンポーネントが無限にレンダリングされます

私はuseEffectフックを使用しており、応答時にアクションをディスパッチして保存する関数 getStoreUsers を使用してフェッチ呼び出しでユーザーデータのリストを取得します shopUsers (これは配列です)reduxストア内。

配列の依存関係では、 [shopUsers] と記述しています。なぜそれが無限のレンダリングを引き起こしているのか分かりません。

次に、useEffectフックの使用方法を示します。

useEffect(() => {
    const { getStoreUsers, shopUsers } = props;
    setLoading(true);
    getStoreUsers().then(() => {
      setLoading(false);
    }).catch(() => {
      setLoading(false);
    });
  }, [shopUsers]);

ShopUsers配列内のデータが変更された場合にのみ、コンポーネントを再レンダリングします。

配列依存関係の中にshopUsers.lengthを書いた場合。再レンダリングを停止します。

しかし、ユーザーがuserListをクリックして次のページでユーザーデータを更新したときに開くページがあるとします。更新後、ユーザーは、以前にマウント解除されていない同じコンポーネントに戻ってほしいと思います。したがって、この場合、配列の長さは同じままですが、配列インデックスの内部のデータが更新されます。そのため、この場合、shopUsers.lengthは機能しません。

2

あなたはあなたが望むことをするためにカスタムフックを作ることができます:

この例では、配列の最後の要素を置き換え、コンソールに出力を表示します。

import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
import { isEqual } from "lodash";

const usePrevious = value => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};

const App = () => {
  const [arr, setArr] = useState([2, 4, 5]);
  const prevArr = usePrevious(arr);

  useEffect(() => {
    if (!isEqual(arr, prevArr)) {
      console.log(`array changed from ${prevArr} to ${arr}`);
    } 
  }, [prevArr]);

  const change = () => {
    const temp = [...arr];
    temp.pop();
    temp.Push(6);
    setArr(temp);
  };

  return (
      <button onClick={change}>change last array element</button>
  )
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

実際の例 ここ

7
Colin Ricardo

エフェクトは「shopUsers」プロップに基づいてトリガーされます。「shopUsers」プロップ自体が「shopUsers」プロップを更新するreduxアクションをトリガーし、それが無限に発砲し続ける理由です。

最適化したいのはコンポーネント自体のレンダリングだと思います。すでにreduxを使用しているため、props/stateは不変であるため、React.memoは、その小道具の1つが変更された場合にのみコンポーネントを再レンダリングします。

また、state/props変数は、関数全体のスコープで使用されるため、フックの外で定義する必要があります。

あなたの場合、メモの2番目のパラメーターとして空の配列を渡すと、ComponentDidMountでのみ起動します。null/ undefinedを渡すか、何も渡さない場合、最適化したい場合は、ComponentDidMount + ComponentDidUpdateで起動されます。小道具が変更/コンポーネントが更新されても、特定の変数が変更されない限り、フックは起動しません。その場合、2番目の引数として変数を追加できます。

React.memo(function(props){
  const [isLoading, setLoading] = useState(false);
  const { getStoreUsers, shopUsers } = props;
  useEffect(() => {
    setLoading(true);
    getStoreUsers().then(() => {
      setLoading(false);
    }).catch((err) => {
      setLoading(false);
    });
  }, []);
...
})
2
Khaled Osman