React this.setState方法使用原理分析介绍

目录
  • 摘要
  • 1.异步的setState
  • 2.多个setState方法
  • 3.手动实现mySetState

摘要

这一篇文章,主要是简单的实现一下this.setState方法,为了实现该方法,就要知道this.setState方法具有什么特点。

首先在React组件中,我们先定义一个state和setState方法:

  myState = {
    value: 0
  }
  mySetState = ( changeState ) =>{
    this.setState(
      this.myState
    )
  }

这里可能会说,为什么在自己写的mySetState 方法里还要调用React的setState呢?都调用人家的了还算自己写的吗?

由于在React中,render只能处理通过setState方法修改的值,所以这里我们在mySetState 中调用了一下。但是mySetState方法的具体实现还是我们自己去完成。

1.异步的setState

首先,我们看一段代码:

  state = {
    value: 0
  }
    setTimeout(() => {
      console.log('SetTimeOut ---- '+this.state.value);
    }, 0);
    new Promise((resolve,reject) => {
      resolve(this.state.value)
    })
    .then(res => {
      console.log('Promise ---- '+res);
    })
    this.setState({
      value: this.state.value+1
    })
    console.log(this.state.value);

这段代码会输出什么呢?

由这个结果我们可以知道上面的代码执行顺序:

(1)console.log(this.state.value);

(2)Promise代码

(3)setState方法

(4)setTimeOut方法

所以setState一定是一个异步的方法。

在实现的时候,要注意异步的问题。

2.多个setState方法

我们继续看一段代码:

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

这段代码输出的会是1还是5呢?

答案是1,这是React为了效率所作的一个优化。防止每次setState都会导致render重新渲染!

而如果我就想要这个效果,React也是提供了一个解决办法,就是setState方法可以接受一个函数作为参数:

    this.setState( (preState) => {
      return {
        value: preState.value+1
      }
    } )
    this.setState( (preState) => {
      return {
        value: preState.value+1
      }
    } )
    this.setState( (preState) => {
      return {
        value: preState.value+1
      }
    } )
    this.setState( (preState) => {
      return {
        value: preState.value+1
      }
    } )
    setTimeout(() => {
      console.log(this.state.value);
    }, 0);

preState代表的是上一个state。

3.手动实现mySetState

OK,有了上面对setState方法分了解,我们可以手动的实现一下mySetState方法

首先解决就是调用多个setState方法的时候,所以我们不能每次调用mySetState方法都让state值更新,也就是这么写:

  mySetState = ( changeState ) =>{
    Object.assign(this.myState,changeState)
    this.setState(
      this.myState
    )
  }

我们只需要知道最后一个changeState,所以这里我们维护一个队列,用来保存所有的changeState,然后每次调用mySetState 方法的时候,将changeState放到队列里面:

  queue = []
  mySetState = ( changeState ) =>{
    Promise.resolve().then(()=>{
      this.stateShift()
    })
    this.queue.push(changeState)
    this.setState(
      this.myState
    )
  }

重头戏来了,我们已经有了这个队列,那我们是如何让这个队列的changeState 出来的呢?

这里我们写一个方法:

  stateShift() {
    let empty;
    while(empty = this.queue.shift()){
    }
  }

通过迭代器的方式,遍历队列。empty就是拿到的每个changeState 。changeState 有两种形式,对象的时候肯定是很好写的。

  stateShift() {
    let empty;
    while(empty = this.queue.shift()){
      if(typeof empty === 'object'){
        Object.assign(this.myState,empty)
      }
  }

只需要让新出来的去替换旧的就可以了。如果changeState 是一个方法,这个时候,我们需要手动去维护一个preState变量,这个变量的作用就是用来保存上一个state。

所以具体的实现应该为:

  stateShift() {
    let empty;
    while(empty = this.queue.shift()){
      if(!this.preState){
        this.preState =  Object.assign({},this.myState)
      }
      if(typeof empty === 'object'){
        Object.assign(this.myState,empty)
      }else if(typeof empty === 'function'){
        Object.assign(this.myState,empty(this.preState))
      }
      this.preState = this.myState
    }
  }

最后一步,这个方法应该什么时候调用。其实需要注意的无非就是,要在所有的changeState 都放到队列中,再进行调用。

而this.queue.push(changeState)这段代码又是同步的代码,所以在它之前,通过异步的方式调用,就可以实现出这种效果:

  mySetState = ( changeState ) =>{
    Promise.resolve().then(()=>{
      this.stateShift()
    })
    this.queue.push(changeState)
    this.setState(
      this.myState
    )
  }

最后将整个实现代码附上:

import React, { Component } from 'react'
export default class Child extends Component {
  state = {
    value: 0
  }
  myState = {
    value: 0
  }
  queue = []
  mySetState = ( changeState ) =>{
    Promise.resolve().then(()=>{
      this.stateShift()
    })
    this.queue.push(changeState)
    this.setState(
      this.myState
    )
  }
  stateShift() {
    let empty;
    while(empty = this.queue.shift()){
      if(!this.preState){
        this.preState =  Object.assign({},this.myState)
      }
      if(typeof empty === 'object'){
        Object.assign(this.myState,empty)
      }else if(typeof empty === 'function'){
        Object.assign(this.myState,empty(this.preState))
      }
      this.preState = this.myState
    }
  }
  add = ()=>{
    //测试代码
    // this.mySetState( (pre) => {
    //   return {
    //     value: pre.value + 1
    //   }
    // } )
    // this.mySetState( (pre) => {
    //   return {
    //     value: pre.value + 1
    //   }
    // } )
    // this.mySetState( (pre) => {
    //   return {
    //     value: pre.value + 1
    //   }
    // } )
    // this.mySetState({
    //   value: this.myState.value+1
    // })
    // this.mySetState({
    //   value: this.myState.value+1
    // })
    // this.mySetState({
    //   value: this.myState.value+1
    // })
    // this.mySetState({
    //   value: this.myState.value+1
    // })
    setTimeout(() => {
      console.log('SetTimeOut ---- '+this.myState.value);
    }, 0);
    new Promise((resolve,reject) => {
      resolve(this.myState.value)
    })
    .then(res => {
      console.log('Promise ---- '+res);
    })
    this.mySetState({
      value: this.myState.value+1
    })
    console.log(this.myState.value);
  }
  render() {
    return (
      <div>
        <span>{this.myState.value}</span>
        <br></br>
        <button onClick={this.add}>++</button>
      </div>
    )
  }
}

最后值得注意的是,这里只是针对于setState的一些特点去模拟了一下setState的实现,具体的源码可能不会像这样简单!

到此这篇关于React this.setState方法使用原理分析介绍的文章就介绍到这了,更多相关React this.setState内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 关于React中setState同步或异步问题的理解

    目录 1. setState同步?异步? 2. 表现为异步 1. React 合成事件 2. 生命周期函数 3. 表现为同步 1. 原生事件 2. setTimeout 4. setState的第二个参数 1. setState同步?异步? 在 React 的类式组件中,我们可以使用setState方法更新state状态.但有些时候使用setState之后,得不到最新的数据. 其实 React 中setState本身执行的过程和代码是同步的,只是因为 React 框架本身的性能优化机制而导致的.

  • react纯函数组件setState更新页面不刷新的解决

    目录 问题描述: 原因分析: 解决方案: 补:react中,hooks钩子时useState更新不渲染组件的问题 问题描述: const [textList, setTextList] = useState(原数组); setTextList(新数组); 当修改原数组时,如果原数组是个深层数组(不只一层),使用setTextList修改时,不会触发页面刷新 原因分析: 这个涉及到可变对象he不可变对象的知识,在vue和react中,如果更新可变对象时,可能会引起视图更新,这是因为,vue和rea

  • React中setState同步异步场景的使用

    目录 setState同步异步场景 描述 原理 保证内部数据统一 启用并发更新 参考 setState同步异步场景 React通过this.state来访问state,通过this.setState()方法来更新state,当this.setState()方法被调用的时候,React会重新调用render方法来重新渲染UI.相比较于在使用Hooks完成组件下所需要的心智负担,setState就是在使用class完成组件下所需要的心智负担,当然所谓的心智负担也许叫做所必须的基础知识更加合适一些.

  • 详细谈谈React中setState是一个宏任务还是微任务

    目录 前言 面试官的问法是否正确?§ React 是如何控制 setState 的 ?§ 未来会有异步的 setState§ 总结 前言 最近有个朋友面试,面试官问了个奇葩的问题,也就是我写在标题上的这个问题. 能问出这个问题,面试官应该对 React 不是很了解,也是可能是看到面试者简历里面有写过自己熟悉 React,面试官想通过这个问题来判断面试者是不是真的熟悉 React

  • React 组件中的state和setState()你知道多少

    目录 state的基本使用 setState()修改状态 解决方法: 总结 state的基本使用 状态(state)即数据,是组件内部的私有数据,只能在组件内部使用 state的值是对象,可以通过this.state来获取状态. setState()修改状态 状态是可变的,可以通过this.setState({要修改的数据})来改变状态 注意:跟vue语法不同,不要直接修改state中的值,这时错误的! //正确 this.setState({ count:this.state.count+1

  • 浅谈React多个setState会调用几次

    目录 1. 两个setState,调用几次? 2. 两个setState,调用的是哪一个? 3. 两个setState放在setTimeout中? 4. 总结 1. 两个setState,调用几次? 如下代码所示,state中有一个count.对按钮绑定了点击事件,事件中执行了两次setState,每次都将count的值加1. 当点击按钮时,setState会执行几次?render()会执行几次? 答案:都是1次. state = { count: 0 }; handleClick = () =

  • React 中的 setState 是同步还是异步

    setState 是同步还是异步?肯定是异步的呀. 确定么?那看一下这段代码会打印什么: import { Component } from 'react'; class Dong extends Component { constructor() { super(); this.state = { count: 0 } } componentDidMount() { setTimeout(() => { this.setState({ count: 1 }); console.log(this

  • React 中 setState 的异步操作案例详解

    目录 前言 React 中的 setState 为什么需要异步操作? 什么时候setState会进行同步操作? 前言 在使用state的时候, 如果我们企图直接修改state中的某一个值之后直接打印(使用)他,就会发现,他其实并没有改变. 就像下面的例子,企图通过点击事件之后就使用修改之后的state的值,但是会发state中的并没有被立即修改,还是原先的值,我们都知道那是因为 setState就相当于是一个异步操作,不能立即被修改. import React, { Component } fr

  • 代码解析React中setState同步和异步问题

    React起源于Facebook的内部项目.React的出现是革命性的创新,React的是一个颠覆式的前端框架.在React官方这样介绍的它:一个声明式.高效.灵活的.创建用户界面的JavaScript库,即使React的主要作用是构建UI,但是项目的逐渐成长已经使得react成为前后端通吃的WebApp解决方案. angular中用的是watcher对象,vue是观察者模式,react就是state了,他们各有各的特点,没有好坏之分,只有需求不同而选择不同. React的官方网址:https:

  • React this.setState方法使用原理分析介绍

    目录 摘要 1.异步的setState 2.多个setState方法 3.手动实现mySetState 摘要 这一篇文章,主要是简单的实现一下this.setState方法,为了实现该方法,就要知道this.setState方法具有什么特点. 首先在React组件中,我们先定义一个state和setState方法: myState = { value: 0 } mySetState = ( changeState ) =>{ this.setState( this.myState ) } 这里可

  • React createElement方法使用原理分析介绍

    目录 摘要 1.创建方法 2.处理type 3.处理config 4.处理children 5.对比真正的React.createElement源码 摘要 在上一篇说过,React创建元素有两种方式: 第一种是通过JSX方式创建,第二种是通过React.createElement方法创建.但是通过JSX创建React元素的方式,最终也会经过babel进行转换,再用React.createElement进行元素创建. 而这一篇文章,主要是讲一下React.createElement是如何创建Rea

  • js中数组排序sort方法的原理分析

    本文实例分析了js中数组排序sort方法的原理.分享给大家供大家参考.具体分析如下: 最近在百度的项目中要用到对数组进行排序,当然一开始自然想到了数组的sort方法,这方法应用非常简单,大致如下: 复制代码 代码如下: window.onload=function(){         var arr=[2,55,55,1,75,3,9,35,70,166,432,678,32,98];         var arr2=["George","John","

  • Android延迟实现的几种解决方法及原理分析

    前言 在Android开发中我们可能会有延时执行某个操作的需求,例如我们启动应用的时候,一开始呈现的是一个引导页面,过了两三秒后,会自动跳转到主界面.这就是一个延时操作. 而写这篇文章的目的,是看到群里有人在实现延迟的时候,用如下的第四种方法,个人感觉有点不妥,为了防止更多的人有这种想法,所以自己抽空深入分析,就分析的结果,写下此文,希望对部分人有启示作用. 1.实现延迟的几种方法? 答: 1.java.util.Timer类的: public void schedule(TimerTask t

  • Spring Validation方法实现原理分析

    最近要做动态数据的提交处理,即需要分析提交数据字段定义信息后才能明确对应的具体字段类型,进而做数据类型转换和字段有效性校验,然后做业务处理后提交数据库,自己开发一套校验逻辑的话周期太长,因此分析了Spring Validation的实现原理,复用了其底层花样繁多的Validator,在此将分析Spring Validation原理的过程记录下,不深入细节 如何使用Spring Validation Spring Bean初始化时校验Bean是否符合JSR-303规范 1.手动添加BeanVali

  • jQuery的ready方法实现原理分析

    jQuery中的ready方法实现了当页面加载完成后才执行的效果,但他并不是window.onload或者doucment.onload的封装,而是使用 标准W3C浏览器DOM隐藏api和IE浏览器缺陷来完成的,首先,我们来看jQuery的代码 DOMContentLoaded = function() { //取消事件监听,执行ready方法 if ( document.addEventListener ) { document.removeEventListener( "DOMContent

  • Android增量升级的方法和原理详细介绍

    总结:我们使用delta编码算法减少Android应用升级程序的大小.我们通过bsdiff和bspatch工具在android上实现delta编码算法.服务器软件和android应用已经部署.当前,我们能够减少Android升级流量的50%,如果大量的部署,这将会减少网络的压力. 升级机制:我们打算采用delta编码的patch升级Android应用.新的升级机制可以描述如下: 1.  在服务器上生成一个patch.2.  下载patch到手机中.3.  通过补丁获取一个已安装应用的新的安装ap

  • 一文详解React Redux使用方法

    目录 一.理解JavaScript纯函数 1.1 纯函数的概念 1.2 副作用概念的理解 1.3 纯函数在函数式编程的重要性 二.Redux的核心思想 2.1 为什么需要 Redux 2.2 Redux的核心概念 2.2.1 store 2.2.2 action 2.2.3 reducer 2.3 Redux的三大原则 2.3.1 单一数据源 2.3.2 State是只读的 2.3.3 使用纯函数来执行修改 2.4 Redux 工作流程 三.Redux基本使用 3.1 创建Store的过程 3.

  • React插槽使用方法

    目录 需求 核心思想 React实现插槽的两种方式 需求 我们自己写了个组件,引用组件时想要在组件中写入内容,并且写入的内容可以被组件识别.控制,用过Vue的同学肯定会立刻想到slot插槽,react也支持插槽功能,下面我们用react开发一个支持插槽功能的组件. 核心思想 父组件在子组件中传入的三个div,这三个div会默认通过props传到子组件中,然后我们在子组件中控制children的渲染即可. 核心代码 // 015 使用插槽 import React from 'react'; im

  • 浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)

    我们通过前篇:<浅谈web上存漏洞及原理分析.防范方法(安全文件上存方法)>,已经知道后端获取服务器变量,很多来自客户端传入的.跟普通的get,post没有什么不同.下面我们看看,常见出现漏洞代码.1.检测文件类型,并且用用户上存文件名保存 复制代码 代码如下: if(isset($_FILES['img'])){    $file = save_file($_FILES['img']); if($file===false) exit('上存失败!'); echo "上存成功!&qu

随机推荐