在使用 graphql 的 useQuery 获取的数据更新 useEffect 钩子内的状态变量时防止无限渲染
Posted
技术标签:
【中文标题】在使用 graphql 的 useQuery 获取的数据更新 useEffect 钩子内的状态变量时防止无限渲染【英文标题】:Prevent infinite renders when updating state variable inside useEffect hook with data fetched using useQuery of graphql 【发布时间】:2020-10-12 12:25:45 【问题描述】: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.
现在,根据反应,状态更新必须在没有突变的情况下完成,因为我每次需要更新状态时都会创建一个新对象。但是通过设置一个新的状态变量对象,我的组件被重新渲染,导致无限渲染。
如何以这样一种方式实现它,即我将所有变量传递给我的 useEffect 依赖数组,并让它只执行一次 useEffect。
请注意:如果我不将 stateOfValue 变量添加到依赖项中,它会起作用,但这是在撒谎。
Here is the reproduced link.
【问题讨论】:
不将stateOfValue
添加到依赖项中可能不会撒谎 - 您不会在 useEffect 中使用它,因此它实际上不是依赖项,省略它很好
【参考方案1】:
我想你误会了
你想在依赖数组中的是[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]);
【讨论】:
否,效果依赖于 someOperation 会导致无限重新渲染或过时关闭 它确实解决了这个问题的荒谬示例,但我猜 oncompleted 会更好地将 graphql 数据复制到本地状态。还;如果无法运行,请不要创建 sn-p。【参考方案2】:如果要在效果中设置状态,可以执行以下操作:
const data = useQuery(query);
const [stateOfValue, setStateOfValue] = useState();
const someOperation = useCallback(
() =>
setStateOfValue((current) => ( ...current, data )),
[data]
);
useEffect(() => someOperation(), [someOperation]);
每次数据更改时,都会重新创建函数 SomeOperation 并导致效果运行。在某些时候数据被加载或者出现错误并且数据没有被重新创建导致 someOperation 不能被再次创建并且效果不能再次运行。
【讨论】:
【参考方案3】:首先我会问您是否需要将stateOfValue
存储为状态。如果没有(例如,它不会被其他任何东西编辑),您可能会使用 useMemo
挂钩
const myComputedValue = useMemo(() => someOperation(data), [data]);
现在myComputedValue
将是someOperation
的结果,但它只会在数据更改时重新运行
如果需要将其存储为状态,您可以使用useQuery
中的onCompleted
选项
const data = useQuery(query,
onCompleted: response =>
let newValue = someOperation();
setStateOfValue(newValue);
)
【讨论】:
以上是关于在使用 graphql 的 useQuery 获取的数据更新 useEffect 钩子内的状态变量时防止无限渲染的主要内容,如果未能解决你的问题,请参考以下文章
无法在异步方法中获取查询,无法从外部导入 graphql 查询
无法使用 React-Query + Graphql-Request 在 useQuery 中传递参数
如何在 GraphQL 中正确链接 useQuery 和 useMutation?
如何使用 Apollo 客户端 useQuery 钩子防止不必要的重新获取?