使用 React Hooks 获得“太多重新渲染”错误

Posted

技术标签:

【中文标题】使用 React Hooks 获得“太多重新渲染”错误【英文标题】:Getting a "Too many re-renders" error with React Hooks 【发布时间】:2021-11-21 08:57:22 【问题描述】:

我在这里为 React Hooks 苦苦挣扎。我在网上查看,但无法弄清楚如何将示例调整到我的代码中。我有以下组件会触发“重新渲染过多”错误:

const EmailVerification = () => 
  const [showMessage, setShowMessage] = useState(true);
  const [text, setText] = useState("...Loading. Do not close.");

  const  data, error  = useQuery(VERIFY_EMAIL);
  if (error) setText(genericErrorMessage);
  if (data) setText(emailVerificationMessage);

  return (
    <Wrapper>
      <Message setShowMessage=setShowMessage text=text />
    </Wrapper>
  )

如何重新组织我的代码以避免此错误?我知道 useEffect 钩子应该用于执行副作用,虽然我不知道在这种情况下如何使用它(假设它是必要的)。

【问题讨论】:

【参考方案1】:

触发错误是因为您在渲染函数中直接使用setText。该函数在调用后渲染组件。因为在下一次渲染中,dataerror 仍然设置,所以它再次调用了setText

关于useEffect,你是对的。使用useEffect,您可以确保仅在数据发生更改时才调用setText 函数。在您的情况下,这适用于 data 和/或 error 变量。

import  useEffect  from 'react';

const EmailVerification = () => 
  const [showMessage, setShowMessage] = useState(true);
  const [text, setText] = useState("...Loading. Do not close.");

  const  data, error  = useQuery(VERIFY_EMAIL);
  
  useEffect(() => 
    if (error) setText('message');
    if (data) setText('emailVerificationMessage');
  , [error, data]);
  
  return (
    <Wrapper>
      <Message setShowMessage=setShowMessage text=text />
    </Wrapper>
  )

但是,由于您只是使用现有的道具更改 text 变量,因此您也可以仅在 JS(X) 中执行此操作:


const EmailVerification = () => 
  const [showMessage, setShowMessage] = useState(true);
  const  isLoading, data, error  = useQuery(VERIFY_EMAIL);
  
  const text = isLoading ? 'Loading... Do not close' : error || !data ? 'Error message' : 'emailVerificationMessage';

  return (
    <Wrapper>
      <Message setShowMessage=setShowMessage text=text />
    </Wrapper>
  )

这使用嵌套的三元运算符(不是风扇),可以用任何其他方法替换。

【讨论】:

优秀的答案。谢谢你,克里斯。【参考方案2】:

setText 将导致重新渲染,并将在下一次渲染时再次调用。据我了解,您希望在查询返回错误或数据后设置文本。

为避免这种情况,请使用 onError 和 onCompleted ,您可以像这样传递给 useQuery :

const  data, error  = useQuery(VERIFY_EMAIL, 
  onCompleted: () => setText(emailVerificationMessage),
  onError: () => setText(genericErrorMessage)
);

并删除这两行:

if (error) setText(genericErrorMessage);
if (data) setText(emailVerificationMessage);

或在 useEffect 中调用 setText:

useEffect(() => 
  if (error) 
    setText(genericErrorMessage)
  
, [error])

【讨论】:

useQuery 回调,不错! 天哪,我为什么没有考虑这个解决方案?非常感谢!!

以上是关于使用 React Hooks 获得“太多重新渲染”错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 React Hooks 多次获取数据 axios

useEffect 中的 state 总是使用 React Hooks 引用初始状态

react自定义hooks-自动改变页面的title,Http请求hooks等..(持续更新)

react---Hooks的基本使用---巷子

ReactReact全家桶React Hooks

ReactReact全家桶React Hooks