react的this.setState详细介绍

1,050 阅读3分钟
this.setState是react类组件中最常用的一个react API,使用它可以改变state从而改变页面。今天我们就来详细的学习一下这个东西。比如:
import React, { Component } from react;

export default class Test extends Component {
	constructor() {
		super()
		this.state = { 
			count: 0,
		}
	}
	render() {
		return (
			<div>
			您的点击数:{this.state.count}
		<button onClick={() => this.setState({ count: this.state.count + 1 })}>
					点击数+1
				</button>
			</div>
		)
	}
} 

这样当你每点击button按钮一次,上面的点击数就会+1
但是this.setState还有很多的知识点你没有了解,真正项目当中可能会出现很多你不理解的bug。
比如说:

  • this.setState是异步的
    在你调用了this.setState后在他的下面输出他的结果还是没变的状态

    this.setState({ count: this.state.count + 1 }) console.log(this.state.count) //结果还是之前的,而不是+1之后的

  • this.setState的第一个参数可以是一个对象,也可以是一个函数返回一个对象,函数的参数是上一次的state

示例:

this.setState((prevState) => ({ prevState.count + 1 })); 
  • this.setState的第二个参数是它的回调函数,在前面重新给state赋值后执行

示例:

this.setState({
	count: this.state.count + 1,
}, () => console.log(this.state.count)) //结果是+1之后的count 
  • 连续调用this.setState的结果

示例:

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

虽然调用了三次 setState ,但是 count 的值还是为 1。因为多次调用会合并为一次,只有当更新结束后 state 才会改变,三次调用等同于如下代码:

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

如果想让最后的结果等于3请用上面介绍的this.setState()的参数为函数返回对象的形式。
或者像下面这样:

<u>额外注意点</u>

但是如果把上面的代码改装一下效果就不一样了
在计时器中:

setTimeout(() => {
	this.setState({ count: this.state.count + 1 })
	this.setState({ count: this.state.count + 1 })
	this.setState({ count: this.state.count + 1 })
}, 100) 

这时候这三次都会被执行到。

或者在原生事件中:

import React, {Component} from 'react';

class Index extends Component {
  constructor(props) {
    super(props);
    this.state = {
      val: 0,
    }
  }
  componentDidMount() {
    document.getElementById("id").onclick = () => {
      this.setState({val:this.state.val+1});
      console.log(this.state.val);

      this.setState({val:this.state.val+1});
      console.log(this.state.val);
    };
  }
  render() {
    return (
        <div id={'id'}>
          111
        </div>
    );
  }
}

export default Index; 
小总结:
  • setState 只在合成事件和钩子函数中是“异步”的,在原生事件【比如在componentDidMount中给dom挂载事件】和 setTimeout 中都是同步的。
  • setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
  • setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

react会对原生的dom事件进行收集拦截合成分发,就是有自己的事件系统,除了自己手动使用addeventlistener或者on监听的事件都会走react合成事件系统

为什么setState在计时器中是同步的

说直白点就是和react在同一事件循环中的才是异步,不在同一事件循环中就是同步的,setTimeout就是另一个事件循环中的事,这么说可能不是很准确,但好理解