不可变值
不能直接修改 state的值,必须通过this.setState修改状态值
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
class App extends Component {
constructor(props) {
super(props);
this.state = {
list: [1,2,3,4],
obj: {name1:'张三',name2: '李四'}
}
}
handleClick = () =>{
const listCopy = this.state.list.slice();
listCopy.push(100);
this.setState({
// list: [...this.state.list,100], //追加
// list: this.state.list.concat(100) //追加
// list: this.state.list.slice(1) //截取
// list: listCopy //生成副本 对副本怎么操作都不会影响原状态数组
})
}
handleClick2 = () =>{
this.setState({
// obj: {...this.state.obj,...{name3: '王五'}}
obj : Object.assign(this.state.obj, {name3: '王五'})
})
}
render() {
return ( <div>
{this.state.list.join(' ')} <br/>
<button onClick={this.handleClick}> 修改数组</button>
<button onClick={this.handleClick2}> 修改对象</button>
</div> );
}
}
export default App;
ReactDOM.render(<App />,document.getElementById('root'));
注意不可以使用 push pop splice 修改状态 因为会改变原数组。违反不可变值
当状态是对象或者数组时,修改状态不可以改变原对象或者数组的值。可以使用结构赋值等方法,返回一个全新的数组或者对象进行更新状态操作
this.setState方法是同步更新还是异步更新
在react控制的事件中或者在react生命周期中使用this.setState 是异步的
在元素dom事件 或者setTimeout是同步的
this.state = {
count: 0
}
render() {
componentDidMount () {
this.setState({count:this.state.count+1});
console.log(this.state.count); // 这里是异步更新
const button = document.getElementById('button');//绑定原生的事件方法 不受react控制 修改状态是同步的
button.addEventListener('click',()=>{
this.setState({count:this.state.count+1});
console.log(this.state.count); // 这里是同步更新
})
}
handleClick3 = () =>{
this.setState({count:this.state.count+1});
console.log(this.state.count); // 这里是异步的
}
//定时器内修改 同步
setTimeClick = () =>{
setTimeout(() => {
this.setState({count:this.state.count+1});
console.log(this.state.count); // 这里是同步的
}, 0);
}
return ( <div>
{this.state.count}
<button onClick={this.handleClick3}> + react事件 异步</button>
<button id='button'>+ js原生事件 同步</button>
<button onClick={this.setTimeClick}>定时器 + 同步</button>
</div> );
}
修改状态可能会被合并
constructor(props) {
super(props);
this.state = {
count2:0
}
}
hebing = () =>{
this.setState({count2:this.state.count2+1}) //状态会被合并
this.setState({count2:this.state.count2+1})
this.setState({count2:this.state.count2+1})
}
render() {
return ( <div>
<h1>count2: {this.state.count2}</h1>
<button id='button'>+ js原生事件 同步</button>
</div> );
}
在上面的例子中状态只会被加一次 结果为1
hebing = () =>{
this.setState((state)=>({
count2: state.count2+1
}))
this.setState((state)=>({
count2: state.count2+1
}))
this.setState((state)=>({
count2: state.count2+1
}))
}
运用函数的方式修改可以避免状态更新异常 结果为3
hebing = () =>{
// this.setState({count2:this.state.count2+1})
// this.setState({count2:this.state.count2+1})
// this.setState({count2:this.state.count2+1})
this.setState((state)=>({
count2: state.count2+1
}))
this.setState({count2:this.state.count2+1})
this.setState((state)=>({
count2: state.count2+1
}))
}
注意不要对象和函数混用 第一次执行setState,count为1,第二次执行,this.state仍然是没有更新的状态,所以this.state.count又打回了原形为0,加1以后变成1,最后再执行setState,所以最终count的结果是2。(render依然只执行一次)
setState的第二个回调参数会在更新state,重新触发render后执行。
修改状态对象和函数如何选择
修改状态时,当要依赖原状态的时候建议使用函数方式进行修改。当修改的状态与原状态没有关系的时候建议使用对象方式。