前言

React通过管理状态实现对组件的管理,通过this.setState()方法更新state,触发render()方法重新渲染页面,而在更新前有一个shouldComponentUpdate可以控制state更新是否触发render,方便不必要的渲染,而state里最好放入与渲染有关的属性,而渲染无关的使用class的属性对象保存使用即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class Demo extends Component{
constructor(props){
super(props);
this.state = {name:"zhang"}; // state
this.objState = {currPage:0}; // 不必要渲染的对象使用
}
changePage(){
this.objState.currPage++;
}
render(){
return (
<div>{this.state.name}</div>
)
}
}

state注意事项

1、使用state是要遵循react的规则,state是不可变的,需要使用特定的函数更新state,如state在constructor定义后不能对它直接进行赋值操作,而是要使用setState,否则不会触发渲染render,而是直接修改了state,在下次使用setState后直接覆盖掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Demo extends Component{
constructor(props){
super(props);
this.state = {name:"zhang"}; // state
this.objState = {currPage:0}; // 不必要渲染的对象使用
}
changePage=()=>{
// 这是错误的操作
this.state.name = "测试";
// 正确操作
this.setState({name: "ceshi"});
}
render(){
return (
<div onClick={changePage}>{this.state.name}</div>
)
}
}

2、setState是异步的
由于react的setState的源码里,会先把state的更新推进队列里,等所有的state都进入后才会进行render的渲染操作,而所以在setState后不要直接获取state的数据,因为那些还是旧数据,而是要等调用栈结束后执行渲染操作再获取更新后state,但shouldComponentUpdate与componentWillUpdate接受的参数是更新后state,所以这些在渲染前的钩子函数可以在接收参数里获取更新的state与props,而setState的异步是代码执行顺序实现的,代码里都是同步的

但由于setState在一般的调用时都会放到任务队列里,而把setState的使用放在setTimeout这些异步调用的回调函数里时不会放到任务队列里,而是直接调用,所以在setTimeout这些回调函数里可以直接获取到更新的state。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class ItemOne extends Component {
constructor(props) {
super(props);
this.state={name:"zhang"};
}
change=()=>{
this.setState({name:"vvv"});
setTimeout(()=>{
this.setState({name:"xxx"});
console.log("time:"+this.state.name); // xxx
},0)
}
shouldComponentUpdate(props, state){
console.log(this.state.name)
return true;
}
componentWillUpdate(props, state){
console.log(state);
console.log(this.state.name);
}
componentDidUpdate(){
console.log(this.state.name)
}
render() {
return (
<div className='itemOne'>
<div onClick={this.change}>{this.state.name}</div>
</div>
)
}
}
// 打印
// zhang
// {name: "vvv"}
// zhang
// vvv

3、不要在shouldComponentUpdate与componentWillUpdate使用
在shouldComponentUpdate与componentWillUpdate使用setState会造成死循环,所以浏览器都会在控制台报错。

1
2
// 报错信息
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

4、不涉及渲染state
由于state的更新都会触发render渲染,而有些状态是不需要触发渲染的,那么可以使用一些普通对象保存,而不是使用state管理,因为state与普通对象的差别在于会触发页面的渲染。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Demo extends Component{
constructor(props){
super(props);
this.state = {name:"zhang"}; // state
this.objState = {currPage:0}; // 不必要渲染的对象使用
}
changePage=()=>{
this.objState.currPage++;
}
render(){
return (
<div onClick={changePage}>{this.state.name}</div>
)
}
}

5、componentWillReceiveProps
当一个组件从父组件接受参数;只要父组件的render函数被重新执行了,子组件的这个生命周期就会被执行;
(如果这个组件第一次存在于父组件中,不会执行,如果这个组件之前存在于父组件中,才会执行)
所以无论props使用更新,只要父组件渲染了那么就会触发这个函数