详解React setState数据更新机制

为什么使用setState

在React 的开发过程中,难免会与组件的state打交道。使用过React 的都知道,想要修改state中的值,必须使用内部提供的setState 方法。为什么不能直接使用赋值的方式修改state的值呢?我们就分析一下,先看一个demo。

class Index extends React.Component {
  this.state = {
    count: 0
  }
  onClick = () => {
    this.setState({
       count: 10
    })
  }
  render() {
    return (
      <div>
        <span>{this.state.count}</span>
        <button onClick={this.onClick}>click</button>
      </div>
    )
  }
}

根据上面代码可以看到,点击按钮后把state 中 count 的值修改为 10。并更新页面的显示。所以state的改变有两个作用:对应的值改变 和 **页面更新。**要想做到这两点在react 中 非 setState 不可。 假如说我们把 onClick 的方法内容修改为 this.state.count = 10 并在方法内打印出 this.state 的值,可以看到state的值已经改变。但是页面并没有更新到最新的值。 ☆总结一下:

  • state 值的改变,目的是页面的更新,希望React 使用最新的 state来渲染页面。但是直接赋值的方式并不能让React监听到state的变化。
  • 必须通过setState 方法来告诉React state的数据已经变化。

☆扩展一下:

在vue中,采用的就是直接赋值的方式来更新data 数据,并且Vue也能够使用最新的data数据渲染页面。这是为什么呢? 在vue2中采用的是 Object.defineProperty() 方式监听数据的get 和 set 方法,做到数据变化的监听 在vue3中采用的是ES6 的 proxy 方式监听数据的变化

setState 的用法

想必所有人都会知道setState 的用法,在这里还是想记录一下: setState方法有两个参数:第一个参数可以是对象直接修改属性值,也可以是函数能够拿到上一次的state值。第二个参数是一个可选的回调函数,可以获取最新的state值 回调函数会在组件更新完成之后执行,等价于在 componentDidUpdate 生命周期内执行。

  • 第一个参数是对象时:如同上文的demo一样,直接修改state的属性值
this.setState({
	key:newState
})
  • 第一个参数是函数时:在函数内可以获取上一次state 的属性值。
// prevState 是上一次的 state,props 是此次更新被应用时的 props
this.setState((prevState, props) => {
  return {
      key: prevState.key
  }
})

异步更新还是同步更新

setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式 将 setState() 视为请求而不是立即更新组件的命令。为了更好的感知性能,React 会延迟调用它,然后通过一次传递更新多个组件。React 并不会保证 state 的变更会立即生效。

先修改一下上面的代码,如果在onClick 方法中连续调用三次setState,根据上文可知 setState是一个异步的方式,每次调用只是将更改加入队列,同步调用的时候只会执行最后一次更新,所以结果是1而不是3。

onClick = () => {
  const { count } = this.state
  this.setState({ count: count + 1 })
  this.setState({ count: count + 1 })
  this.setState({ count: count + 1 })
}

可以把上面代码理解为 Object.assign() 方法,

Object.assign(
  state,
  { count: state.count + 1 },
  { count: state.count + 1 },
  { count: state.count + 1 }
)

如果第一个参数传入一个函数,连续调用三次,是不是和传入对象方式的结果是一样的呢?

onClick = () => {
  this.setState((prevState, props) => {
    return {
      count: prevState.count + 1
    }
  })
  this.setState((prevState, props) => {
    return {
      count: prevState.count + 1
    }
  })
  this.setState((prevState, props) => {
    return {
      count: prevState.count + 1
    }
  })
}

结果和传入对象的方式大相径庭,使用函数的方式就能够实现自增为3的效果。这又是为什么呢? 在函数内能够拿到最新的state 和 props值。由上文可知 setState 的更新是分批次的,使用函数的方式确保了当前state 是建立在上一个state 之上的,所以实现了自增3的效果。

☆总结一下: 为什么setState 方法是异步的呢?

  • 可以显著的提升性能,react16 引入了 Fiber 架构,Fiber 中对任务进行了划分和优先级的分类,优先处理优先级比较高的任务。页面的响应就是一个优先级比较高任务,所以如果setState是同步,那么更新一次就要更新一次页面,就会阻塞到页面的响应。最好的办法就是获得到多个更新,之后进行批量的更新。只更新一次页面。
  • 如果同步更新state,但是还没有执行render 函数,那么state 和 props 就不能够保持同步。

**是不是所有的setState 都是异步的形式呢?**答案是 否!!!在React 中也会存在setState 同步的场景

onClick = () => {
	this.setState({ count: this.state.count + 1 })
  console.log(this.state)
  setTimeout(() => {
    this.setState({ count: this.state.count + 1 })
    console.log(this.state)
  }, 0)
}

上面的代码会打印出**0,2。**这又是为什么呢?其实React 中的 setState 并不是严格意义上的异步函数。他是通过队列的延迟执行实现的。使用 isBatchingUpdates 判断当前的setState 是加入到更新队列还是更新页面。当 isBatchingUpdates=ture 是加入更新队列,否则执行更新。

知道了React 是使用 isBatchingUpdates 来判断是否加入更新队列。那么为什么在 setTimeout 事件中 isBatchingUpdates 值为 false ? 原因就是在React中,对HTML的原生事件做了一次封装叫做**合成事件。**所以在React自己的生命周期和合成事件中,可以控制 isBatchingUdates 的值,可以根据值来判断是否更新页面。而在宿主环境提供的原生事件中(即非合成事件),无法将 isBatchingUpdates 的值置为 false,所以就会立即执行更新。

☆所以setState 并不是有同步的场景,而是在特殊的场景下不受React 的控制 **

总结

setState 并不是单纯的同步函数或者异步函数,他的同步和异步的表现差异体现在调用的场景不同。在React 的生命周期和合成事件中他表现为异步函数。而在DOM的原生事件等非合成事件中表现为同步函数。

以上就是详解React setState数据更新机制的详细内容,更多关于React setState数据更新机制的资料请关注我们其它相关文章!

(0)

相关推荐

  • React中setState的使用与同步异步的使用

    在react中,修改状态如果直接使用this.state,不会引起组件的重新渲染,需要通过 this.setState来对组件的属性进行修改. 1.this.setState的两种定义方式 定义初始状态 state = { count: 0 }, 如果此时有一个按钮,点击按钮让计数加1,我们可以有两种写法 (1)传递对象 this.setState({ count: this.state.count + 1}) (2)传递函数 this.setState((state, props) => ({

  • 深入掌握 react的 setState的工作机制

    react 是单向数据流,若想要改变已有组件的外观,我们只能通过更改组件的 props 或者更新组件的 state.在 react 项目的代码中我们操作最多的就是 this.setState 方法.下面对 setState 方法进行详细的说明. <!--more --> setState要点:react 框架为了提高性能,会对 state 的更新进行收集.合并.再进行一次批量的状态更新.这种机制常常导致一些意想不到的情况. setState 有两种调用形式: 向 setState 传递对象 s

  • 详解React中setState回调函数

    在使用React过程中,中可以使用this.state来访问需要的某些状态,但是需要更新或者修改state时,一般而言,我们都会使用setState()函数,从而达到更新state的目的,setState()函数执行会触发页面重新渲染UI.但是!!!setState是异步的!!! 1. 语法: setState(updater[, callback]) // updater是要改变的state对象,callback是state导致的页面重新渲染的回调,等价于componentDidUpdate

  • 详解react setState

    setState是同步还是异步 自定义合成事件和react钩子函数中异步更新state 以在自定义click事件中的setState为例 import React, { Component } from 'react'; class Test extends Component { constructor(props) { super(props); this.state = { count: 1 }; } handleClick = () => { this.setState({ count:

  • 浅谈使用React.setState需要注意的三点

    前言 这篇文章原标题是 3 Reasons why I stopped using React.setState ,但是我对原文作者提出的论点不是很感冒,但是作者提出的三点对 React 新手来说是很容易忽略的地方,所以我在这里只提出部分内容,而且把标题改为 使用React.setState需要注意的三点 . 正文 对 React 新手来说,使用 setState 是一件很复杂的事情.即使是熟练的 React 开发,也很有可能因为 React 的一些机制而产生一些bug,比如下面这个例子: 文档

  • 深入研究React中setState源码

    React作为一门前端框架,虽然只是focus在MVVM中的View部分,但还是实现了View和model的绑定.修改数据的同时,可以实现View的刷新.这大大简化了我们的逻辑,只用关心数据流的变化,同时减少了代码量,使得后期维护也更加方便.这个特性则要归功于setState()方法.React中利用队列机制来管理state,避免了很多重复的View刷新.下面我们来从源码角度探寻下setState机制. 1 还是先声明一个组件,从最开始一步步来寻源: class App extends Comp

  • react学习笔记之state以及setState的使用

    在react中通过 state 以及 setState() 来控制组件的状态. state state 是 react 中用来存储组件数据状态的,可以类比成 vue 中的 data. 1.state的作用 state是React中组件的一个对象.React把用户界面当做是状态机,想象它有不同的状态然后渲染这些状态,可以轻松让用户界面与数据保持一致. React中,更新组件的state,会导致重新渲染用户界面(不要操作DOM).简单来说,就是用户界面会随着state变化而变化. 2.state工作

  • 详解React setState数据更新机制

    为什么使用setState 在React 的开发过程中,难免会与组件的state打交道.使用过React 的都知道,想要修改state中的值,必须使用内部提供的setState 方法.为什么不能直接使用赋值的方式修改state的值呢?我们就分析一下,先看一个demo. class Index extends React.Component { this.state = { count: 0 } onClick = () => { this.setState({ count: 10 }) } re

  • 详解React中key的作用

    要了解React中key的作用,可以从key的取值入手,key的取值可以分为三种,不定值.索引值.确定且唯一值 在下面的代码中,key的取值是不定值(Math.random()) 问题: 点击按钮的时候,span的颜色会变成红色吗? import React, { useState } from 'react'; function App() { const [initMap, setInitMap] = useState([1,2,3,4]); const handleClick = () =

  • 详解React 16 中的异常处理

    详解React 16 中的异常处理 异常处理 在 React 15.x 及之前的版本中,组件内的异常有可能会影响到 React 的内部状态,进而导致下一轮渲染时出现未知错误.这些组件内的异常往往也是由应用代码本身抛出,在之前版本的 React 更多的是交托给了开发者处理,而没有提供较好地组件内优雅处理这些异常的方式.在 React 16.x 版本中,引入了所谓 Error Boundary 的概念,从而保证了发生在 UI 层的错误不会连锁导致整个应用程序崩溃:未被任何异常边界捕获的异常可能会导致

  • 详解React项目的服务端渲染改造(koa2+webpack3.11)

    因为对网页SEO的需要,要把之前的React项目改造为服务端渲染,经过一番调查和研究,查阅了大量互联网资料.成功踩坑. 选型思路:实现服务端渲染,想用React最新的版本,并且不对现有的写法做大的改动,如果一开始就打算服务端渲染,建议直接用NEXT框架来写 项目地址:https://github.com/wlx200510/react_koa_ssr 脚手架选型:webpack3.11.0 + react Router4 + Redux + koa2 + React16 + Node8.x 主要

  • 详解React 条件渲染

    在 React 中,你可以创建不同的组件来封装各种你需要的行为.然后还可以根据应用的状态变化只渲染其中的一部分. React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI. 先来看两个组件: function UserGreeting(props) { return <h1>欢迎回来!</h1>; } function GuestGreeting(props)

  • 详解React的回调渲染模式

    一.一个简单的小例子 1.父组件 <Twitter username='tylermcginnis33'> {(user) => user === null ? <Loading /> : <Badge info={user} />} </Twitter> 2.子组件框架 import React, { Component, PropTypes } from 'react' import fetchUser from 'twitter' // fetc

  • 详解React Fiber的工作原理

    啥是React Fiber? React Fiber,简单来说就是一个从React v16开始引入的新协调引擎,用来实现Virtual DOM的增量渲染. 说人话:就是一种能让React视图更新过程变得更加流畅顺滑的处理手法. 我们都知道:进程大,线程小.而Fiber(纤维)是一种比线程还要细粒度的处理机制.从这个单词也可以猜测:React Fiber会很"细".到底怎么个细法,我们接着往下看. 为什么会有React Fiber? 之前说了,React Fiber是为了让React的视

  • 详解react的两种动态改变css样式的方法

    第一种:动态添加class,以点击按钮让文字显示隐藏为demo import React, { Component, Fragment } from 'react'; import './style.css'; class Demo extends Component{ constructor(props) { super(props); this.state = { display: true } this.handleshow = this.handleshow.bind(this) thi

  • 详解React 父组件和子组件的数据传输

    在学习 React 框架组件间数据传输知识点前,我们需要先明确几点使用原则. React的组件间通讯是单向的.数据必须是由父级传到子级或者子级传递给父级层层传递. 如果要给兄弟级的组件传递数据,那么就要先传递给公共的父级而后在传递给你要传递到的组件位置. 这种非父子关系的组件间传递数据,不推荐使用这种层层传递的方式:而是选择使用维护全局状态功能模块(Redux) 一.父组件向子组件传递数据 父组件向子组件传递数据是通过在父组件中引用子组件时,在子组件标签设置传输数据的属性:而子组件中通过 thi

随机推荐