使用使用 graphql 的 useQuery 获取的数据更新 useEffect 挂钩内的状态变量时防止无限渲染

Prevent infinite renders when updating state variable inside useEffect hook with data fetched using useQuery of graphql

Graphql 提供了 useQuery 钩子来获取数据。每当组件重新渲染时都会调用它。

//mocking useQuery hook of graphql, which updates the data variable
  const data = useQuery(false);

我正在使用 useEffect 挂钩来控制应调用“useQuery”的次数。

我想做的是每当我从 useQuery 收到数据时,我想对数据执行一些操作并将其设置为另一个状态变量“stateOfValue”,它是嵌套对象数据。所以这必须在 useEffect 钩子中完成。

因此我需要添加我的 stateOfValue 和“data”(这有我的 API 数据)变量作为对 useEffect 挂钩的依赖性。

  const [stateOfValue, setStateOfValue] = useState({
    name: "jack",
    options: []
  });

  const someOperation = (currentState) => {
    return {
        ...currentState,
        options: [1, 2, 3]
      };
  }
  useEffect(() => {
    if (data) {
      let newValue = someOperation(stateOfValue);
      setStateOfValue(newValue);
    }
  }, [data, stateOfValue]);

基本上,我将在我的 useEffect 中使用的所有变量添加为依赖项,因为这是正确的做法 according to Dan Abramov.

现在,根据 React,状态更新必须在没有突变的情况下完成,因为我每次需要更新状态时都会创建一个新对象。但是通过设置一个新的状态变量对象,我的组件被重新渲染,导致无限渲染。

如何以将所有变量传递到我的 useEffect 依赖数组并让它只执行一次 useEffect 的方式来实现它。

请注意: 如果我不将 stateOfValue 变量添加到依赖项,它会起作用,但那会撒谎。

Here is the reproduced link.

我想你误会了 您希望在依赖项数组中的内容是 [data, setStateOfValue] 而不是 [data, stateOfValue]。因为你在 useEffect 中使用 setStateOfValue 而不是 stateOfValue 正确的是:

const [stateOfValue, setStateOfValue] = useState({
    name: "jack",
    options: []
  });

  const someOperation = useCallback((prevValue) => {
    return {
        ...prevValue,
        options: [1, 2, 3]
      };
  },[])
  useEffect(() => {
    if (data) {
      setStateOfValue(prevValue => {
        let newValue = someOperation(prevValue);
        return newValue
      });
    }
  }, [data, setStateOfValue,someOperation]);

首先,我想问您是否需要stateOfValue 存储为状态。如果不是(例如,它不会被任何其他东西编辑),你可能会使用 useMemo 钩子来代替

const myComputedValue = useMemo(() => someOperation(data), [data]);

现在myComputedValue将是someOperation的结果,但只有当数据改变

时才会重新运行

如果需要将其存储为状态,您可以使用 useQuery

中的 onCompleted 选项
const data = useQuery(query, {
  onCompleted: response => {
    let newValue = someOperation();
    setStateOfValue(newValue);
  }
)

如果您想在效果中设置状态,您可以执行以下操作:

const data = useQuery(query);
const [stateOfValue, setStateOfValue] = useState({});
const someOperation = useCallback(
  () =>
    setStateOfValue((current) => ({ ...current, data })),
  [data]
);
useEffect(() => someOperation(), [someOperation]);

每次数据更改时,都会重新创建函数 SomeOperation 并导致效果 运行。在某些时候加载数据或出现错误并且不会再次创建数据导致不会再次创建 someOperation 并且效果不会再次 运行。