一、组件state
1,设计合适的state
state必须能代表一个组件UI呈现的完整状态集,代表一个组件UI呈现的最小状态集。
state必须能代表一个组件UI呈现的完整状态集又可以分成两类数据:用作渲染组件时使用到的数据的来源,用作组件UI展现形式的判断依据:
class Hello extends Component {
constructor(props) {
super(props);
this.state = {
user: 'react', //用作渲染组件时使用到的数据的来源
display: true //用作组件UI展现形式的判断依据
}
}
render() {
return (
<div>
{
this.state.display ? <h1>{this.state.user}</h1> : <></>
}
</div>
)
}
}
export default Hello;
普通属性:
在es6中,可以使用this.属性名定义一个class的属性,也可以说属性是直接挂载在this下的一个变量。因此,state和props实际上也是组件的属性,只不过是react在Component class中预定义好的属性。除了state和props以外的其他组件属性称为组件的普通属性。
class Hello extends Component {
constructor(props) {
super(props);
this.timer = null; //普通属性
this.state = {
date: new Date()
}
this.updateDate = this.updateDate.bind(this);
}
componentDidMount(){
this.timer = setInterval(this.updateDate, 1000);
}
componentWillUnmount(){
clearInterval(this.timer);
}
updateDate(){
this.setState({
date: new Date()
})
}
render() {
return (
<div>
<h1>{this.state.date.toString()}</h1>
</div>
)
}
}
export default Hello;
组件中用到的一个变量是否应该作为state可以通过下面4条依据判断:
- 这个变量是否通过props从父组件中获取?如果是,那么它不是一个状态
- 这个变量是否在生命周期中都保持不变?如果是,那么它不是一个状态
- 这个变量是否可以通过其他状态(state)或者属性(props)计算得到?如果是,那么它不是一个状态
- 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态,这种情况更适合定义为组件的一个普通属性
2,正确修改state
①不能直接修改state,需要使用setState()
②state的更新是异步的
React会将多次setState的状态合并成一次状态修改,不能依赖当前的state计算下一个state(props也是异步的)。
例如:连续两次点击加入购物车,实际数量只会加1,在React合并多次修改为1次的情况下,相当于执行了:
Object.assign(
previousState,
{quantity: this.state.quantity + 1},
{quantity: this.state.quantity + 1}
)
这种情况下,可以使用另一个接收一个函数作为参数的setState,这个函数有两个参数,第一个是当前修改后的最新状态的前一个状态preState,第二个参数是当前最新的属性props:
this.setState((preState,props) => ({
quantity: preState.quantity + 1;
}))
③state的更新是一个合并的过程
④state与不可变对象
直接修改state,组件不会render;state包含的所有状态都应该是不可变对象,当state中某个状态发生变化时,应该重新创建这个状态对象,而不是直接修改原来的状态。创建新的状态有以下三种方法:
- 状态的类型是不可变类型(数字、字符串、布尔值、null、undefined):因为状态是不可变类型,所以直接赋一个新值即可
- 状态的类型是数组:可以使用数组的concat或者es6的扩展语法,slice方法、filter方法。不能使用push、pop、shift、unshift、splice等方法修改数组类型的状态,因为这些方法会在原数组基础上修改。
this.setState((preState) => ({
arr: [...preState.arr,'react'];
}))
this.setState((preState) => ({
arr: preState.arr.concat(['react'])
}))
- 状态的类型是普通对象(不包含字符串、数组):使用ES6的Object.assgin方法或者对象扩展语法