IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> react中setState()的执行策略是什么?如何合并的那?如何控制合并? -> 正文阅读

[JavaScript知识库]react中setState()的执行策略是什么?如何合并的那?如何控制合并?

学习react你一定使用了它的setState,那么它的更新策略是什么那?内部是如何运行的那?下面内容给你解释清楚。
react开发对setState的使用可能一点也不陌生,但肯定会碰到过这种情况

import React from 'react'

export default class BatchedDemo extends React.Component {
    state = {
        number: 0,
    }

    handleClick = () => {
        this.countNumber()
	}

    countNumber() {

        this.setState({
            number: this.state.number + 1
        })

        this.setState({
            number: this.state.number + 4
        })

        this.setState({
            number: this.state.number + 10
        })
    }

    render() {
        return <button id="myButton" onClick={this.handleClick}>Num: {this.state.number}</button>
    }
}

运行结果为 10 这是为什么那?
这就是我们下面需要说到的 更新策略了

setState批量更新

  • 除了 虚拟DOM 外,减少更新频率的另一个手段就是React的批量更新。
  • 顾名思义,批量处理就是,可以避免短期内的多次渲染,攒为一次更新。

setState()合并策略

经过测试发现:一次更新的意思就是,覆盖原来的,而不是叠加原来的
正如上面的那个结果一样:结果为10 而不是 15。

那 s e t S t a t e 是 如 何 合 并 的 那 ? 是 否 可 以 控 制 合 并 那 ? \color{red}{那setState是如何合并的那?是否可以控制合并那?} setState

setState的合并原理:

setState实现:

setState(newState) {
    if (this.canMerge) {
        this.updateQueue.push(newState)
        return 
    }

    // 下面是真正的更新: dom-diff, lifeCycle...
    ...
}

然后countNumber()方法调用之后,把隐式操作通过伪代码显示出来:

countNumber() {
		this.canMerge = true

        this.setState({
            number: this.state.number + 11
        })

        this.setState({
            number: this.state.number + 20
        })

        this.setState({
            number: this.state.number + 5,
        })
        
 		this.canMerge = false

		 // 通过this.updateQueue合并出finalState
	    const finalState = ...  
	    // 此时canMerge 已经为false 故而走入时机更新逻辑
	    this.setState(finaleState) 
}

可以看出 setState首先会判断是否可以合并,如果可以合并this.canMerge = true
,就直接返回了。直到this.canMerge = false时,代表finalState已经合并完成,就开始走更新,需要注意的是这些都是react内部的隐式操作,是发生在React内部的,React对它们有完全的控制权。

canMerge逻辑存在于哪里?

除了事件处理函数会执行canMerge逻辑,在执行componentDidMount前后也会有canMerge逻辑,可以理解为:React委托代理了所有的事件,在执行你的函数/componentDidMount之前,会执行React逻辑,这样React也是有时机执行canMerge逻辑的。

如何控制canMerge逻辑

批量更新是极好滴!我们当然希望任何setState都可以被批量,关键点在于React是否有时机执行canMerge逻辑,也就是React对目标函数有没有控制权。如果没有控制权,那么就不会执行canMerge逻辑,也就不会发生setState()被react隐式合并了

通过setTimeout脱离react的控制

import React from 'react'

export default class BatchedDemo extends React.Component {
    state = {
        number: 0,
    }

    handleClick = () => {

        this.setState({
            number: this.state.number + 1
        })
        this.setState({
            number: this.state.number + 2
        })
        this.setState({
            number: this.state.number + 3
        })

        setTimeout(() => {
            this.setState({
                number: this.state.number + 4
            })
            this.setState({
                number: this.state.number + 5
            })
            this.setState({
                number: this.state.number + 6
            })
        })

    }
    render() {
        return <button id="myButton" onClick={this.handleClick}>Num:
        {this.state.number}
        </button>
    }
}

分析上述代码:

handleClick 是事件回调,React有时机执行canMerge逻辑,所以x为+1,+2,+3是合并的,handleClick结束之后canMerge被重新设置为false。注意这里有一个setTimeout(fn, 0)。 这个fn会在handleClick之后调用,而React对setTimeout并没有控制权,React无法在setTimeout前后执行canMerge逻辑,所以x为4,5,6是无法合并的,所以fn这里会存在3次dom-diff。React没有控制权的情况有很多: Promise.then(fn), fetch回调,xhr网络回调等等。

所以点击按钮: 3+4+5+6=18

通过unstable_batchedUpdates重回react的控制
以上代码的setTimeout中,我想让react去拿回控制权,合并代码,怎么办呢?
需要用unstable_batchedUpdates这个API
代码如下:

import React from 'react'
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom'

export default class BatchedDemo extends React.Component {
    state = {
        number: 0,
    }

    handleClick = () => {

        this.setState({
            number: this.state.number + 1
        })
        this.setState({
            number: this.state.number + 2
        })
        this.setState({
            number: this.state.number + 3
        })

        setTimeout(() => {
            //通过这个api,让react拿回控制权,执行canMerge逻辑
            batchedUpdates(() => {
                this.setState({
                    number: this.state.number + 4
                })
                this.setState({
                    number: this.state.number + 5
                })
                this.setState({
                    number: this.state.number + 6
                })
            })
        })
    }
    render() {
        return <button id="myButton" onClick={this.handleClick}>Num:
        {this.state.number}
        </button>
    }
}

打印如下:3+6=9

最后看一下这个api的伪代码:

function unstable_batchedUpdates(fn) {
    this.canMerge = true

    fn()

    this.canMerge = false
    const finalState = ...  //通过this.updateQueue合并出finalState
    this.setState(finaleState)
}

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-24 15:27:49  更:2021-08-24 15:30:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:15:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码