React 18 state 状态更新函数

这篇具有很好参考价值的文章主要介绍了React 18 state 状态更新函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

参考文章

把一系列 state 更新加入队列

设置组件 state 会把一次重新渲染加入队列。但有时可能会希望在下次渲染加入队列之前对 state 的值执行多次操作。为此,了解 React 如何批量更新 state 会很有帮助。

React 会对 state 更新进行批处理

在下面的示例中,可能会认为点击 “+3” 按钮会使计数器递增三次,因为它调用了 setNumber(number + 1) 三次:

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
    </>
  )
}

但是,每一次渲染的 state 值都是固定的,因此无论调用多少次 setNumber(1),在第一次渲染的事件处理函数内部的 number 值总是 0

setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);

但是这里还有另外一个影响因素需要讨论。React 会等到事件处理函数中的 所有 代码都运行完毕再处理 state 更新。 这就是为什么重新渲染只会发生在所有这些 setNumber() 调用 之后 的原因。

这让你可以更新多个 state 变量——甚至来自多个组件的 state 变量——而不会触发太多的 重新渲染。但这也意味着只有在事件处理函数及其中任何代码执行完成 之后,UI 才会更新。这种特性也就是 批处理,它会使 React 应用运行得更快。它还会帮你避免处理只更新了一部分 state 变量的令人困惑的“半成品”渲染。

React 不会跨 多个 需要刻意触发的事件(如点击)进行批处理——每次点击都是单独处理的。请放心,React 只会在一般来说安全的情况下才进行批处理。这可以确保,例如,如果第一次点击按钮会禁用表单,那么第二次点击就不会再次提交它。

在下次渲染前多次更新同一个 state

这是一个不常见的用例,但是如果想在下次渲染之前多次更新同一个 state,可以像 setNumber(n => n + 1) 这样传入一个根据队列中的前一个 state 计算下一个 state 的 函数,而不是像 setNumber(number + 1) 这样传入 下一个 state 值。这是一种告诉 React “用 state 值做某事”而不是仅仅替换它的方法。

现在尝试递增计数器:

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(n => n + 1);
        setNumber(n => n + 1);
        setNumber(n => n + 1);
      }}>+3</button>
    </>
  )
}

在这里,n => n + 1 被称为 更新函数。当将它传递给一个 state 设置函数时:

  1. React 会将此函数加入队列,以便在事件处理函数中的所有其他代码运行后进行处理。
  2. 在下一次渲染期间,React 会遍历队列并给你更新之后的最终 state。
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);

下面是 React 在执行事件处理函数时处理这几行代码的过程:

  1. setNumber(n => n + 1)n => n + 1 是一个函数。React 将它加入队列。
  2. setNumber(n => n + 1)n => n + 1 是一个函数。React 将它加入队列。
  3. setNumber(n => n + 1)n => n + 1 是一个函数。React 将它加入队列。

当在下次渲染期间调用 useState 时,React 会遍历队列。之前的 number state 的值是 0,所以这就是 React 作为参数 n 传递给第一个更新函数的值。然后 React 会获取上一个更新函数的返回值,并将其作为 n 传递给下一个更新函数,以此类推:

更新队列 n 返回值
n => n + 1 0 0 + 1 = 1
n => n + 1 1 1 + 1 = 2
n => n + 1 2 2 + 1 = 3

React 会保存 3 为最终结果并从 useState 中返回。

这就是为什么在上面的示例中点击“+3”正确地将值增加“+3”

如果在替换 state 后更新 state 会发生什么

这个事件处理函数会怎么样?你认为 number 在下一次渲染中的值是什么?

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        setNumber(n => n + 1);
      }}>增加数字</button>
    </>
  )
}

这是事件处理函数告诉 React 要做的事情:

  1. setNumber(number + 5)number0,所以 setNumber(0 + 5)。React 将 “替换为 5 添加到其队列中。
  2. setNumber(n => n + 1)n => n + 1 是一个更新函数。 React 将 该函数 添加到其队列中。

在下一次渲染期间,React 会遍历 state 队列:

更新队列 n 返回值
“替换为 5 0(未使用) 5
n => n + 1 5 5 + 1 = 6

React 会保存 6 为最终结果并从 useState 中返回。

注意:setState(x) 实际上会像 setState(n => x) 一样运行,只是没有使用 n

如果在更新 state 后替换 state 会发生什么

让我们再看一个例子。你认为 number 在下一次渲染中的值是什么?

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        setNumber(n => n + 1);
        setNumber(42);
      }}>增加数字</button>
    </>
  )
}

以下是 React 在执行事件处理函数时处理这几行代码的过程:

  1. setNumber(number + 5)number0,所以 setNumber(0 + 5)。React 将 “替换为 5 添加到其队列中。
  2. setNumber(n => n + 1)n => n + 1 是一个更新函数。React 将该函数添加到其队列中。
  3. setNumber(42):React 将 “替换为 42 添加到其队列中。

在下一次渲染期间,React 会遍历 state 队列:

更新队列 n 返回值
“替换为 5 0(未使用) 5
n => n + 1 5 5 + 1 = 6
“替换为 42 6(未使用) 42

然后 React 会保存 42 为最终结果并从 useState 中返回。

总而言之,以下是可以考虑传递给 setNumber state 设置函数的内容:

  • 一个更新函数(例如:n => n + 1)会被添加到队列中。
  • 任何其他的值(例如:数字 5)会导致“替换为 5”被添加到队列中,已经在队列中的内容会被忽略。

事件处理函数执行完成后,React 将触发重新渲染。在重新渲染期间,React 将处理队列。更新函数会在渲染期间执行,因此 更新函数必须是 纯函数 并且只 返回 结果。不要尝试从它们内部设置 state 或者执行其他副作用。在严格模式下,React 会执行每个更新函数两次(但是丢弃第二个结果)以便帮助你发现错误。

命名惯例

通常可以通过相应 state 变量的第一个字母来命名更新函数的参数:

setEnabled(e => !e);
setLastName(ln => ln.reverse());
setFriendCount(fc => fc * 2);

如果你喜欢更冗长的代码,另一个常见的惯例是重复使用完整的 state 变量名称,如 setEnabled(enabled => !enabled),或使用前缀,如 setEnabled(prevEnabled => !prevEnabled)文章来源地址https://www.toymoban.com/news/detail-645465.html

摘要

  • 设置 state 不会更改现有渲染中的变量,但会请求一次新的渲染。
  • React 会在事件处理函数执行完成之后处理 state 更新。这被称为批处理。
  • 要在一个事件中多次更新某些 state,可以使用 setNumber(n => n + 1) 更新函数。

到了这里,关于React 18 state 状态更新函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React 18 用 State 响应输入

    参考文章 React 控制 UI 的方式是 声明式 的。不必直接控制 UI 的各个部分,只需要声明组件可以处于的不同状态,并根据用户的输入在它们之间切换。这与设计师对 UI 的思考方式很相似。 当设计 UI 交互时,可能会去思考 UI 如何根据用户的操作而响应 变化 。想象一个允许用

    2024年02月12日
    浏览(30)
  • React 18 state 如同一张快照

    参考文章 也许 state 变量看起来和一般的可读写的 JavaScript 变量类似。但 state 在其表现出的特性上更像是一张快照。设置它不会更改已有的 state 变量,但会触发重新渲染。 可能会认为用户界面会直接对点击之类的用户输入做出响应并发生变化。在 React 中,它的工作方式与这

    2024年02月13日
    浏览(46)
  • React 18 在组件间共享状态

    参考文章 有时候,希望两个组件的状态始终同步更改。要实现这一点,可以将相关 state 从这两个组件上移除,并把 state 放到它们的公共父级,再通过 props 将 state 传递给这两个组件。这被称为“状态提升”,这是编写 React 代码时常做的事。 在这个例子中,父组件 Accordion 渲

    2024年02月10日
    浏览(44)
  • React 18 迁移状态逻辑至 Reducer 中

    参考文章 对于拥有许多状态更新逻辑的组件来说,过于分散的事件处理程序可能会令人不知所措。对于这种情况,可以 将组件的所有状态更新逻辑整合到一个外部函数中 ,这个函数叫作 reducer 。 随着组件复杂度的增加,将很难一眼看清所有的组件状态更新逻辑。例如,下面

    2024年02月10日
    浏览(60)
  • React Hook入门小案例 在函数式组件中使用state响应式数据

    Hook是react 16.8 新增的特性 是希望在不编写 class的情况下 去操作state和其他react特性 Hook的话 就不建议大家使用class的形式了 当然也可以用 这个他只是不推荐 我们还是先创建一个普通的react项目 我们之前写一个react组件可以这样写 简单说 就是声明一个类对象 然后在里面 写组

    2024年02月09日
    浏览(53)
  • 【前端】React快速入门+Redux状态管理

    本文旨在记录react的基础内容,帮助有需要的同学快速上手,需要进一步了解描述更加稳妥和全面的信息,请查阅官方文档 官方文档点击这里进行跳转 react框架 vue,react,angular这几种主流前端框架使用频率较高…本质还是js库。 React.js是一个用于构建用户界面的JavaScript库。它由

    2024年02月12日
    浏览(50)
  • React突变状态,更新数据(对象或者数组),页面数据不刷新的问题

    ​ 刚开始开发时,我们可能会遇到这样的问题,使用useState创建对象或者数组时,setState时,页面未进行更新。这里其实是一个突变状态的问题 什么是突变状态? ​ 当我们给 setState 一个基本数据类型时, state 值将会是 一个不可变的值 ​ 更新时, state 的 原始值也不会被更

    2024年02月11日
    浏览(51)
  • React中的组件的渲染函数(Render Function)是什么?什么是React中的函数组件和类组件?如何在React中进行状态管理?

    React中的组件可以有多种形式的渲染函数,包括传统的render()方法,以及近年来兴起的函数组件和Hooks中的useState()和useEffect()。在这篇文章中,我将详细介绍渲染函数,以及如何在React中使用它们。 渲染函数(Render Function)是指组件在生命周期中的一个特殊方法,它的作用是根据

    2024年02月13日
    浏览(41)
  • React源码解析18(5)------ 实现函数组件【修改beginWork和completeWork】

    经过之前的几篇文章,我们实现了基本的jsx,在页面渲染的过程。但是如果是通过函数组件写出来的组件,还是不能渲染到页面上的。 所以这一篇,主要是对之前写得方法进行修改,从而能够显示函数组件,所以现在我们在index.js文件中,修改一下jsx的写法。修改成函数组件

    2024年02月13日
    浏览(38)
  • 前端react入门day04-useEffect与Hook函数

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 useEffect 的使用 useEffect 的概念理解 useEffect 依赖项参数说明 useEffect — 清除副作用 自定义Hook实现 React Hooks使用规则 useEffect是一个React Hook函数,用于在React组件中 创建不

    2024年01月22日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包