React官方文档学习记录(二)- state

一点点记录,建议需要学习React的移步官方文档去学习。

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
37
38
class Clock extends React.Component {
constructor(props) {
super(props); //1.2构造函数中有个对象,对this.state进行初始化
this.state = {date: new Date()};
}
componentDidMount() { //3.1 当clock被插入到dom中的时候,就开始调用这个生命循环钩子了
this.timerID = setInterval( //3.2这里的钩子是生成了一个计时器,让浏览器定时调用this.tick()函数。
() => this.tick(), //这里疯狂调用tick()函数,然后进行对自身的刷新??
1000
);
}
componentWillUnmount() { //5.1 当clock这个组件不在dom中的时候就调用这个方法。
clearInterval(this.timerID);
}
tick() { //4.1 这里调用tick(),这个函数就是用来设置setState,这里面包含了一个现在时间的对象,然后调用render(),进行更新,如果有改变会进行修改。
this.setState({
//使用this.setStete()将更新定制schedule到(??这里的翻译究竟为什么这么奇怪呢)组件当前的状态中
date: new Date()
});
}
render() { //2.1 使用render进行渲染
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />, //1.1 先去找构造函数
document.getElementById('root')
);

让我们重新简要概述一下整个过程发生了什么以及这些方法被调用的顺序吧:

  1. <Clock />传递到React.DOM.render()的时候,React会去寻找<Clock />这个组件的构造函数(constructor)。既然Clock需要显示现在的时间,它会用一个包含了现在时间的对象(object)初始化this.state,我们之后会更新这个state。
  2. React之后会调用Clock这个组件的render()方法。就是通过这样React知道应该将什么渲染到屏幕上。React之后会更新DOM来匹配Clock的渲染输出。
  3. Clock的输入被插入到DOM之后,React会调用componentDidMount这个生命循环钩子。在这个钩子中,Clock组件会要求浏览器创建一个计时器,让它每秒去调用这个组件的tick()方法。
  4. 之后每秒这个浏览器会调用tick()这个方法,在这其中,这个Clock组件会安排一个UI组件更新,这是通过调用setState()来实现的(它会又一个包含了现在时间的对象)。就是通过这个调用,然后才知道状态是如何改变的,然后就会再调用render()这个方法来知道现在到底应该显示什么在屏幕上。就是因为每次的this.state.timerender()这个方法中都是不同的,所以在渲染结果中会包含这个新更新的时间。然后React就会相应地更新这个DOM。
  5. 如果之后Clock组件从DOM中移除,React就会调用componentWillUnmount这个生命循环钩子,然后这个计时器就停止了。

(感觉官方文档上这一块讲的还是非常清楚的)

如何正确使用state呢

1.不要直接修改状态this.state,一定是需要写在对this.setState({})对象中的。
你唯一可以指定this.state的地方就是在构造函数(constructor)中。

//wrong
this.state.comment = ‘Hello’;
//correct
this.setState({comment: ‘hello’});

2.状态的改变应该是异步的。因为为了显示效果,每次更新的时候,React是分批处理多个setState()的调用的。因为this.propsthis.state可能更新的时候是异步的。计算下一个状态的时候不应该通过依赖它们的值进行改变。

//wrong
this.setState({
counter: this.state.counter + this.props.increment,
})
correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));

3.状态的更新是合并的。当你调用setState的时候,React会合并你提供的对象到当前的state中。但是也要知道这个合并是浅合并,就是当你调用this.setState({comments})的时候并不会对this.state.posts进行修改,只会替代this.state.comments

就像这样,你的state中可以包含几种独立的变量:

1
2
3
4
5
6
7
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}

然后通过分别使用不同的setState()进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}

向下的数据流

(这里我的理解好像是大家都是独立的组件,互相之间应该是互不干扰的,这就是状态经常被认为是本地的或者是概述的的原因。除非你拥有并且设置它,否则你不可以接触任何一个组件。)

一个组件可以选择将它的状态以props的形式向下传递给它的子组件。

就像是可以这样写

1
<h2> It is {this.state.date.toLocaleTimeString()}.</h2>

但是也可以用用户自己定义的一个组件

1
<FormattedDate date={this.state.date} />

然后这个FormattedDate组件就接收date作为它的props,而且对于这个函数来说,它不知道这个参数来自于Clock的state,或是Clock的props,或者是手动输入的参数值。

1
2
3
function FormattedDate(props) {
return <h2>It is {props.date.toLocaleTimeString()}.</h2>
}

(但是不清楚将这个参数继续传递下去的用处是什么)

这就是一个数据流,只能影响接下来(below)的那些组件。你可以想象一棵“组件树”,就像是props的瀑布一样,每个组件的state都像是添加进去的新的水资源,虽然是非常任意(arbitrary),但是仍然是向下流动的。

反正就是只要记住各个组件之间运行的时候都是互不影响的啦~