最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 深入认识React中的setState

    正文概述 掘金(viceroey)   2021-06-28   351

    前言

    在React 16.8.0版本之前还并未出现HOOK,当时大部分的开发都是使用类组件编写的,那么如果一个组件有自己可维护的状态(State)必须要使用setState函数来改变状态中的数据,有时我们经常会遇到一些非常奇怪的现象,比如使用setState改变状态后立即使用状态中的数据竟然不是实时的等等。本章就深入认识一下setState,解决一些你可能会遇到的坑。

    1. setState对状态的改变到底是同步的还是异步的?

    要搞懂setState对状态的改变到底是同步,我做了个实验,一个是由HTML事件触发使用的setState改变状态,一个是由setInterval定时器使用setState改变状态。

    import React from 'react'
    export default class App extends React.Component {
    	state = {
    		n: 10,
    	}
    
    	handler = () => {
    		this.setState({
    			n: this.state.n + 1,
    		});
    		console.log(this.state.n);
    	}
    
    	render() {
    		console.log("组件重新渲染啦~");
    		return (
    			<div>
    				{this.state.n}
    				<button onClick={this.handler}>+</button>
    			</div>
    		)
    	}
    }
    

    深入认识React中的setState

    点击button之后使用setState改变状态再打印会发现,n的值还是刚开始的10,页面上已经是11了,而且打印也在render函数之前,此时可以证明在html事件中setState对状态的改变是异步的。

    接下来我在setInterval中调用setState看看此时对状态的改变是同步的还是异步的。

    export default class App extends React.Component {
    	state = {
    		n: 10,
    	}
    
    	componentDidMount(){
    		this.timer = setInterval(()=>{
    			this.setState({
    				n: this.state.n - 1,
    			});
    			console.log(this.state.n);
    		}, 1000);
    	}
    
    	render() {
    		console.log("组件重新渲染啦~");
    		return (
    			<div>
    				{this.state.n}
    			</div>
    		)
    	}
    }
    

    深入认识React中的setState

    从控制台打印结果可以看出来,数据不仅是同步的,而且还在render的函数调用也在打印之前,可以理解为此时setState为同步的。

    那么为什么会出现这样的情况呢?别着急,接下来看一个例子你就明白react官方的良苦用心了

    export default class App extends React.Component {
    	state = {
    		n: 10,
    	}
    
    	handler = ()=> {
    		this.setState({
    			n: this.state.n + 1,
    		});
    
    		this.setState({
    			n: this.state.n + 1,
    		});
    
    		this.setState({
    			n: this.state.n + 1,
    		});
    
    		console.log(this.state.n);
    	}
    
    	render() {
    		console.log("组件重新渲染啦~");
    		return (
    			<div>
    				{this.state.n}
    				<button onClick={this.handler}>+</button>
    			</div>
    		)
    	}
    }
    

    深入认识React中的setState

    为什么在执行handler函数中多次执行setState方法点击后只加1呢?聪明的小伙伴可能已经想到了,因为如果setState改变状态是HTML元素触发的事件时,那么它对状态的改变就是异步的,所以不难理解,为什么每次只是+1,因为每次使用setState设置状态的时候,此时是异步的还未执行改变n的值,所以三次+1,每次的n还是未改变的n。

    那么为什么要这样设计呢?在我们真实的开发环境中场景肯定不会这么简单,基本上对状态的改变是来自于HTML的事件,比如用户的一些操作,如果不使用异步的话,那么对性能的消耗是非常大的,如果用户的操作会发送网络请求时数据量过大会造成页面的卡死,不仅如此,官方还对异步改变的setState进行了优化,从上面截图可以看出异步改变了状态后才执行render函数进行重新渲染,其实内部原理是将多个setState处理函数添加到了一个队列,当队列中对状态的处理全部改变后才会调用render函数,避免了渲染性能的浪费。

    2. 如果遇到某个事件中,需要对状态修改多次改如何拿到最新状态呢?

    也非常简单,使用setState的第二个参数,参数为一个回调函数,当改变状态后会立即执行回调函数,可以确保状态是最新的。例如:

    export default class App extends React.Component {
    	state = {
    		n: 10,
    	}
    
    	handler = ()=> {
    		this.setState({
    			n: this.state.n + 1,
    		},()=>{
    			this.setState({
    				n: this.state.n + 1,
    			},()=>{
    				this.setState({
    					n: this.state.n + 1,
    				},()=>{
    					console.log(this.state.n); 
    				});
    			});
    		});
    	}
    
    	render() {
    		console.log("组件重新渲染啦~");
    		return (
    			<div>
    				{this.state.n}
    				<button onClick={this.handler}>+</button>
    			</div>
    		)
    	}
    }
    

    深入认识React中的setState

    当使用这种回调函数后,每次状态改变后立马会执行第二个参数中当回调函数,当点击按钮后,n的值+3了。但是这种方法稍微有些繁琐,我们可以把setState的参数直接变成一个函数使用函数的返回值来作为最新状态,例如:

    export default class App extends React.Component {
    	state = {
    		n: 10,
    	}
    
    	handler = ()=> {
    		this.setState((curState)=>{
    			// curState表示的为当前的状态
    			// 该函数的返回值会混合(覆盖)掉之前的状态
    			// 该函数是异步执行
    			return {
    				n: curState.n + 1,
    			}
    		});
    		this.setState(cur=>({n: cur.n + 1}));
    		this.setState(cur=>({n: cur.n + 1}));
    	}
    
    	render() {
    		console.log("组件重新渲染啦~");
    		return (
    			<div>
    				{this.state.n}
    				<button onClick={this.handler}>+</button>
    			</div>
    		)
    	}
    }
    

    此时运行的结果,与使用第二个参数回调函数的效果是一样的。

    总结

    setState,它对状态的改变,可能是异步的 如果改变状态的代码处于某个HTML元素的事件中,则其是异步的,否则是同步 如果遇到某个事件中,需要同步调用多次,需要使用函数的方式得到最新状态

    最佳实践:
    1.把所有的setState当作是异步的
    
    2.永远不要信任setState调用之后的状态
    
    3.如果要使用改变之后的状态,需要使用回调函数(setState的第二个参数)
    
    4.如果新的状态要根据之前的状态进行运算,使用函数的方式改变状态(setState的第一个函数)
    

    React会对异步的setState进行优化,将多次setState进行合并(将多次状态改变完成后,再统一对state进行改变,然后触发render),至此,setState的所有秘密都被我们扒出来了,只要记得最佳实践就能万无一失,文章中有错误的地方或者改进的地方欢迎留言,谢谢。


    起源地下载网 » 深入认识React中的setState

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元