React系列: setState以及setState更新机制

在React中,数据是自顶向下单向流动的,即从父组件到子组件。这样组件之间的关系变得简单并且可预测。

state和props是React组件中最重要的改建,如果顶层组件初始化props, 那么React会向下遍历整颗组件树,重新尝试渲染所有的子组件。而state只关心每个组件自己内部的状态,这些状态只能在组件内部改变。

当组件内部使用内置方法setState时,该组件就会尝试重新渲染,因为我们改变了内部状态,组件需要更新。

改变组件内部状态 setState

1. 不能直接修改State, 要使用setState构造函数时唯一可以给this.state赋值的地方

//构造函数时唯一可以给this.state赋值的地方
class MyComponent extends React.Component {
	constructor(){
		this.state = {
			name: 'test'
		}
	}
}

//修改组件内部状态
this.setState({
	name: 'newName'
})

2. setState是一个异步方法,一个生命周期内所有的setState会合并操作

可以让setState接受一个函数,这个函数用上一个state作为参数,本次更新被应用时的props作为第二个参数。

this.setState((state, props) => ({
  counter: state.counter + props.increment
}));
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
});

3. setState 传入一个对象或函数,和 一个函数赋值结束后执行该函数

this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
},function(){
	console.log(123)
});

//或者
this.setState({
	name: 'newName'
},function(){
	console.log(123)
})

setState源码

Component.prototype.setState = function (partialState, callback) {
//第一个参数可以是对象,函数或者null
  !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0;
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

为什么setState是异步更新?

React通过this.state来访问state, 通过this.setState()方法来更新state, 当this.setState()被调用时,React会重新调用render方法来重新渲染UI

1. 为什么不能用this.state = {}来修改state?

setState通过队列机制实现state更新, React也正是通过状态队列实现了setState的异步更新,避免频繁的重复更新state

当执行setState时,会将需要更新的state合并后放入状态队列,不会立即更新。

如果直接修改this.state就不会被放入状态队列。

当下次调用setState并对状态队列合并时, 会忽略掉之前修改的state,造成错误。

2. setState源码

从上面源码可知,使用setState方法后,调用了enqueueSetState()
源码位置: react-dom\cjs\react-dom.development.js
在这里插入图片描述
enqueueUpdate()将当前组件实例对应的fiber更新到执行队列
scheduleWork()执行一次更新, 会判断isBatchingUpdates,如果true, 执行批量修改,存入队列,如果是false,继续执行更新

例如:
在这里插入图片描述
返回结果是0,0,2,3;

isBatchingUpdates初始是false

componentDidMount开始时,isBatchingUpdates已经变成true了,scheduleWork()方法中会判断本次操作是setState的批量操作,会合并state并存入队列。

componentDidMount接受后,最终会把isBatchingUpdates重置回之前的状态。

setTimeout是宏任务,不在本次执行栈中执行,所以前两次都打印出的是0;

所以setTimeout执行时,isBatchingUpdatesfalse,scheduleWork()会直接执行更新

发布了66 篇原创文章 · 获赞 13 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/haoyanyu_/article/details/101299289
今日推荐