正文从这开始~

总览

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

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

// 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钩子只能在顶层调用。

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钩子都以相同的顺序被调用。

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

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

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钩子只有在上面的条件没有满足时才会被调用。

条件之上

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

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调用之间保留钩子的状态。

React报错之Rendered more hooks than during the previous render的更多相关文章

  1. react 报错的堆栈处理

    react报错 Warning: You cannot PUSH the same path using hash history 在Link上使用replace 原文地址https://reactt ...

  2. React报错 :browserHistory doesn't exist in react-router

    由于版本问题,React中history不可用 import { hashHistory } from 'react-router' 首先应该导入react-router-dom包: import { ...

  3. react报错 TypeError: Cannot read property 'setState' of undefined

    代码如下: class test extends Component { constructor(props) { super(props); this.state = { liked: false ...

  4. React报错之Cannot find name

    正文从这开始~ .tsx扩展名 为了在React TypeScript中解决Cannot find name报错,我们需要在使用JSX文件时使用.tsx扩展名,在你的tsconfig.json文件中把 ...

  5. React报错之Cannot find namespace context

    正文从这开始~ 总览 在React中,为了解决"Cannot find namespace context"错误,在你使用JSX的文件中使用.tsx扩展名,在你的tsconfig. ...

  6. React报错之Expected `onClick` listener to be a function

    正文从这开始~ 总览 当我们为元素的onClick属性传递一个值,但是该值却不是函数时,会产生"Expected onClick listener to be a function" ...

  7. React报错:Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix,

    今天在开发时报了以下错误,记录一下 我们不能在组件销毁后设置state,防止出现内存泄漏的情况 出现原因直接告诉你了,组件都被销毁了,还设置个锤子的state啊 解决方案: 利用生命周期钩子函数:co ...

  8. react报错this.setState is not a function

    当报错这个的时候就要看函数是否在行内绑定this,或者在constructor中绑定this. 我这里犯的错误的是虽然我在constructor中绑定了this,但是语法写的不正确. 错误示范: co ...

  9. React报错之React hook 'useState' is called conditionally

    正文从这开始~ 总览 当我们有条件地使用useState钩子时,或者在一个可能有返回值的条件之后,会产生"React hook 'useState' is called conditiona ...

随机推荐

  1. Acwing785.快速排序

    Acwing785.快速排序 快排模板: y总教学大法好~: #include <iostream> using namespace std; const int N = 1000010; ...

  2. ABAP CDS - DEFINE VIEW, name_list

    Syntax ... ( name1, name2, ... ) ... Effect Defines the element names of a CDS view in ABAP CDS in a ...

  3. FICO 常用事务码

    1.SAP配置流程 1.定义,定义组织,概念,比如FI中定义公司代码,会计科目表,年度变式.SAP中有大量的定义过程. 2.分配,把会计科目表/公司/年度变式等参数分配到公司代码,逻辑组织,基本实现框 ...

  4. Vue 安装 vue的基本使用 vue的初步使用步骤

    1. 资源: https://cn.vuejs.org/v2/guide/#%E8%B5%B7%E6%AD%A5 进入官网学习 2. 点击安装,要把vue下载到本地文件的根目录中,不要选择压缩版的,这 ...

  5. UiPath存在元素Element Exists的介绍和使用

    一.Element Exists的介绍 使您能够验证UI元素是否存在,即使它不可见,输出的是一个布尔值 二.Element Exists在UiPath中的使用 1. 打开设计器,在设计库中新建一个Se ...

  6. Sentiment analysis in nlp

    Sentiment analysis in nlp The goal of the program is to analysis the article title is Sarcasm or not ...

  7. StringJoiner的使用

    1.添加字符串 add()方法 StringJoiner sj = new StringJoiner(","); sj.add("我爱你"); sj.add(& ...

  8. NC20032 [HNOI2003]激光炸弹

    NC20032 [HNOI2003]激光炸弹 题目 题目描述 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标. 现在地图上有 \(n\) (\(N ≤ 10000\))个目标,用整数 ...

  9. [APIO2008]DNA 题解

    题目链接 首先呢,看到 A C G T 对应不同的权值,第一步就是把字母转换成数字. 我们分别对 A->1 C->2 G->3 T->4 进行标号,之后方便 \(\text{d ...

  10. Qt+ECharts开发笔记(二):Qt窗口动态调整大小,使ECharts跟随Qt窗口大小变换而变换大小

    前言   上一篇将ECharts嵌入Qt中,在开始ECharts使用之前,还有一个很重要的功能,就是在窗口变换大小的时候,ECharts的图表尺寸也要跟随Qt窗口变换大小而变换大小.   Demo演示 ...