
每个人都至少有这么一个挚友,
你和他在人生的拐点遇到,
惊叹于彼此的不同或者相似,
有过不少平淡无奇却值得纪念的时光,
任白云苍狗,
风云变幻。
--电影《触不可及》
setState的写法可以分为两类
-
setState(updater, [callback])
第一个参数是一个updater函数;第二个参数是个回调函数(可选)
示例如下:
this.setState((prevState, props) => {
return {counter: prevState.counter + props.step};
});
updater这个函数格式是固定的,这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数(可选),这两个对象setState会自动传递到函数中去
修改开关状态变量经常会用updater来改变状态,例如:
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
-
setState(stateChange, [callback])
第一个参数是一个对象;第二个参数同上也是回调函数(可选)
示例如下:
this.setState({number: 2})
这种方式是我们最常用到的修改state的方式.
setState()将需要处理的变化塞入组件的state对象中, 并告诉该组件及其子组件需要用更新的状态来重新渲染。这是用于响应事件处理和服务端响应的更新用户界面的主要方式。
将setState()认为是一次请求而不是一次立即执行更新组件的命令。为了更为可观的性能,React可能会推迟它,稍后会一次性更新这些组件。React不会保证在setState之后,能够立刻拿到改变的结果。
setState()不是立刻更新组件。其可能是批处理或推迟更新。这使得在调用setState()后立刻读取this.state的一个潜在陷阱。代替地,使用componentDidUpdate 或一个setState回调(setState(updater, callback)),当中的每个方法都会保证在更新被应用之后触发。若你需要基于之前的状态来设置状态,阅读下面关于updater参数的介绍。
state的赋值
下面说一下对state的赋值,分为三种情况:
-
通常情况下的赋值
适用的类型有:数字,字符串,布尔值,null, undefined。示例如下:
this.setState({
count: 1,
title: 'React',
success: true
})
-
数组类型的赋值
如有一个数组类型的状态books,当向books中增加一本书时,使用数组的concat方法或ES6的数组扩展语法(spread syntax):
// 方法一:将state先赋值给另外的变量,然后使用concat创建新数组
var books = this.state.books;
this.setState({
books: books.concat(['三体']);
})
// 方法二:使用preState、concat创建新数组
this.setState(preState => ({
books: preState.books.concat(['三体']);
}))
// 方法三:ES6数组扩展 spread syntax
this.setState(preState => ({
books: [...preState.books, '三体'];
}))
当从books中截取部分元素作为新状态时,使用数组的slice方法:(利用splice返回的数组也是同理)
// 方法一:将state先赋值给另外的变量,然后使用slice创建新数组
var books = this.state.books;
this.setState({
books: books.slice(1,3);
})
// 方法二:使用preState、slice创建新数组
this.setState(preState => ({
books: preState.books.slice(1,3);
}))
当从books中过滤部分元素后,作为新状态时,使用数组的filter方法:
// 方法一:将state先赋值给另外的变量,然后使用filter创建新数组
var books = this.state.books;
this.setState({
books: books.filter(item => {
return item != '三体';
});
})
// 方法二:使用preState、filter创建新数组
this.setState(preState => ({
books: preState.books.filter(item => {
return item != '三体';
});
}))
注意不要使用push、pop、shift、unshift等方法修改数组类型的状态,因为这些方法都是在原数组的基础上修改,而concat、slice、splice、filter能返回一个新的数组。
-
对象类型的赋值
使用ES6 的Object.assgin方法
// 方法一:将state先赋值给另外的变量,然后使用Object.assign创建新对象
var owner = this.state.owner;
this.setState({
owner: Object.assign({}, owner, {name: 'Jason'});
})
// 方法二:使用preState、Object.assign创建新对象
this.setState(preState => ({
owner: Object.assign({}, preState.owner, {name: 'Jason'});
}))
使用对象扩展语法(object spread properties)
// 方法一:将state先赋值给另外的变量,然后使用对象扩展语法创建新对象
var owner = this.state.owner;
this.setState({
owner: {...owner, name: 'Jason'};
})
// 方法二:使用preState、对象扩展语法创建新对象
this.setState(preState => ({
owner: {...preState.owner, name: 'Jason'};
}))
this.setState更新机制图解:

每次setState产生新的state会依次被存入一个队列,然后会根据isBathingUpdates变量判断是直接更新this.state还是放进dirtyComponent里回头再说。 isBatchingUpdates默认是false,也就表示setState会同步更新this.state。 但是,当React在调用事件处理函数之前就会调用batchedUpdates,这个函数会把isBatchingUpdates修改为true,造成的后果就是由React控制的事件处理过程setState不会同步更新this.state。