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

时间:2020-06-22 15:23:04

标签: reactjs graphql react-hooks react-apollo

Graphql提供useQuery挂钩来获取数据。每当组件重新渲染时,它将被调用。

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

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

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

因此,我需要添加我的 stateOfValue 和“ 数据”(具有我的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.的正确方法

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

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

请注意:,如果我不将 stateOfValue 变量添加到依赖项中,它将起作用,但这只是在做出反应。

Here is the reproduced link.

3 个答案:

答案 0 :(得分:2)

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

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]);

答案 1 :(得分:2)

如果要设置效果状态,可以执行以下操作:

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

每次数据更改功能,都会重新创建SomeOperation功能,并使效果运行。有时会加载数据或出现错误,并且不会再次创建数据,从而导致无法再次创建someOperation且效果不会再次运行。

答案 2 :(得分:1)

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

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

现在myComputedValue将是someOperation的结果,但仅在数据更改时才会重新运行

如果有必要将其存储为状态,则可以使用onCompleted中的useQuery选项

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