前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React报错之Rendered more hooks than during the previo

React报错之Rendered more hooks than during the previo

作者头像
用户6256742
发布2024-05-16 14:49:11
1950
发布2024-05-16 14:49:11
举报
文章被收录于专栏:网络日志网络日志

正文从这开始~

总览

当我们有条件地调用一个钩子或在所有钩子运行之前提前返回时,会产生"Rendered more hooks than during the previous render"错误。为了解决该错误,将所有的钩子移到函数组件的顶层,以及不要在条件中使用钩子。

React报错之Rendered more hooks than during the previo
React报错之Rendered more hooks than during the previo

这里有个示例用来展示错误是如何发生的。

代码语言:javascript
复制
// App.js

import {useEffect, useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  // ⛔️ Error: Rendered more hooks than during the previous render.
  if (counter > 0) {
    // 👇️ calling React hook conditionally
    useEffect(() => {
      console.log('hello world');
    });
  }

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

代码的问题在于,我们有条件地调用了useEffect钩子。

顶层调用

为了解决该错误,我们必须将条件移到钩子内部。因为React钩子只能在顶层调用。

代码语言:javascript
复制
import {useEffect, useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  // ✅ hook is called at top level (not conditionally)
  useEffect(() => {
    if (counter > 0) {
      console.log('hello world');
    }
  });

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

我们将if语句移动到了useEffect钩子内部。

这就解决了错误,因为我们必须确保每次组件渲染时,React钩子都以相同的顺序被调用。

这意味着我们不允许在循环、条件或嵌套函数中使用钩子。

这里有另外一个示例用来展示错误是如何发生的。

代码语言:javascript
复制
import {useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  // 👇️ this returns before second hook runs if condition is met
  if (counter > 0) {
    return <h2>Returning early</h2>;
  }

  // ⛔️ Error because hook is called conditionally
  const [color, setColor] = useState('salmon');

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

问题在于,第二个useState钩子只有在上面的条件没有满足时才会被调用。

条件之上

为了解决这个错误,把所有的钩子移到组件的顶层,在任何可能返回值的条件之上。

代码语言:javascript
复制
import {useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  const [color, setColor] = useState('salmon');

  // 👇️ condition that may return early must be below all hooks
  if (counter > 0) {
    return <h2>Returning early</h2>;
  }

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

我们把第二个useState钩子移动到有可能返回一个值的if条件上面。

这是很有帮助的,因为钩子现在在顶层,并且有可预测的行为,允许React在调用useStateuseEffect之间正确地保存状态。

就像文档中所说的那样:

  • 只从React函数组件或自定义钩子中调用Hook
  • 只在最顶层使用 Hook
  • 不要在循环,条件或嵌套函数中调用 Hook
  • 确保总是在你的 React 函数的最顶层以及任何 return 之前使用 Hook

这有助于React在多个useStateuseEffect调用之间保留钩子的状态。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 总览
  • 顶层调用
  • 条件之上
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档