阿波罗钩子超过了最大更新深度

Posted

技术标签:

【中文标题】阿波罗钩子超过了最大更新深度【英文标题】:Maximum update depth exceeded with apollo hooks 【发布时间】:2020-05-24 11:33:48 【问题描述】:

以下代码在点击切换按钮后抛出错误“超出最大更新深度”。

从依赖数组中删除 allJobs 后它可以工作,但我想了解为什么会发生此错误以及如何更好地编写它。

Demo

import React from "react";
import  useQuery  from "@apollo/react-hooks";
import  gql  from "apollo-boost";

const JOBS = gql`
  query Jobs($cursor: String) 
    allJobs(first: 5, after: $cursor) 
      pageInfo 
        hasNextPage
        endCursor
      
      edges 
        node 
          id
          jobTitle
        
      
    
  
`;

const Countries = () => 
  const [visible, setVisible] = React.useState(false);
  const [, setJobs] = React.useState([]);
  const  loading, data  = useQuery(JOBS, 
    fetchPolicy: "cache-and-network"
  );
  const allJobs = data ? data.allJobs.edges.map(edge => edge.node) : undefined;

  React.useEffect(() => 
    if (visible) 
      setJobs(allJobs);
    
  , [visible, allJobs]);

  const toggleVisible = () => 
    setVisible(!visible);
  ;

  if (loading) return <p>Loading...</p>;

  return (
    <>
      <button onClick=toggleVisible>Toggle</button>
      visible &&
        allJobs.map(job => (
          <div key=job.id>
            <p>job.jobTitle</p>
          </div>
        ))
    </>
  );
;

【问题讨论】:

每次渲染,您的allJobs 变量都会重新分配给您的映射节点或undefined。由于它也是您的效果的依赖项,并且您的效果本身会导致重新渲染(如果visible 为真),这会强制效果以递归方式触发。 您可以用useMemo 包裹allJobs 以防止在每次渲染时重新创建此数组。 ***.com/questions/48497358/… - 这个答案可以帮助Maximum update depth exceeded @bsekula 不适用于此处。可以将函数引用传递给 onClick 处理程序。 @tobiasfried 谢谢,它适用于useMemo 【参考方案1】:

为了更好的可见性:

每次渲染,您的 allJobs 变量都会重新分配给您的映射节点或未定义的节点。由于它也是您的效果的依赖项,并且您的效果本身会导致重新渲染(如果可见为真),这会强制效果以递归方式触发。

您可以记住 allJobs 以防止在每次渲染时重新创建它。

const allJobs = React.useMemo(() => 
  return data ? data.allJobs.edges.map(edge => edge.node) : undefined;
, [data]);

Demo

【讨论】:

以上是关于阿波罗钩子超过了最大更新深度的主要内容,如果未能解决你的问题,请参考以下文章

@apollo/client 反应钩子 useQuery() 数据未定义

如何在突变后更新阿波罗缓存(使用过滤器查询)

排毒错误:超过 120000 毫秒的超时。用于异步测试和钩子

Vue几种钩子函数与钩子函数的参数

Vue几种钩子函数与钩子函数的参数

vuejs啥时候使用钩子函数