[React] State & 生命周期(4)
2018-08-07 本文已影响0人
水流云间
state(状态)与props(属性)的差异
state(状态)是私有的,完全受控于当前组件,用于改变组件内容状态的值;
props(属性)用于组件通讯进行传值,是由父级传向子级的,在React中规定不可在子级修改它的值。
如果要实现一个Clock的组件,可以选择通过在父组件里setInterval,改变props中date的值,来实现Clock里展示的改变。
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
但这样耦合度太高,如果能写一次Clock,它自身就能更新,这才是最好的实现方式。
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
定义和设置state
- 定义state,需要在继承自Component的组件的类中,且构造函数是唯一能够初始化
this.state
的地方。 - 调用时使用
this.state.xxx
。 - 使用
setState()
设置state。
class Clock extends React.Component {
// 构造函数
// 父级的props可通过构造函数传入
constructor(props) {
super(props);
this.state = {
date: new Date()
};
}
// 渲染
render() {
return (
<div>
<h1>让人期待时钟-{ this.props.index }</h1>
<p>现在的时间是:{ this.state.date.toLocaleTimeString() }</p>
</div>
);
}
...
}
正确地使用状态(setState()
三大事)
1. 不要直接更新状态,那样并不会重新渲染组件
// Wrong
this.state.comment = 'Hello';
// Correct
this.setState({comment: 'Hello'});
2. 状态更新可能是异步的
React 可以将多个setState()
调用合并成一个调用来提高性能。
因为this.props
和 this.state
可能是异步更新的,你不应该依靠它们的值来计算下一个状态。
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
3. 状态更新合并
当你的状态有多个属性,并且调用setState()
独立地更新它们时,React 将它们的值浅合并到当前状态。
// 两次设置不同的字段值
this.setState({
posts: 12
});
this.setState({
comments: 3
});
// 等同于
this.setState({
posts: 12,
comments: 3
});
生命周期钩子(先暂时列常用的)
-
componentDidMount
在第一次渲染后调用,只在客户端。
之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()
来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout
,setInterval
或者发送AJAX请求等操作(防止异步操作阻塞UI)。
一般用来挂载一些事件,定时器等。 -
componentWillUnmount
在组件从 DOM 中移除的时候立刻被调用。
卸载不需要的事件,定时器等。
用所学知识,写一个完整的Clock组件
- 新建Clock.js文件。
import React from 'react';
class Countdown extends React.Component {
// 构造函数
// 父级的props可通过构造函数传入
constructor(props) {
super(props);
this.state = {
date: new Date()
};
}
// 渲染
render() {
return (
<div>
<h1>让人期待时钟-{ this.props.index }</h1>
<p>现在的时间是:{ this.state.date.toLocaleTimeString() }</p>
</div>
);
}
// 倒计时动作
tick() {
this.setState({
date: new Date()
});
// 参数为:先前的状态,已被应用的props
this.setState((prevState, props) => {
console.log(prevState, props);
});
}
// 组件挂载后执行的生命周期钩子
componentDidMount() {
this.timeId = setInterval(() => {
this.tick();
}, 1000);
}
// 组件将要挂载时执行的生命周期钩子
componentWillUnmount() {
clearInterval(this.timeId);
}
}
export default Clock;
- 在App.js里引用
import React from 'react';
import ReactDOM from 'react-dom';
import Clock from './Clock';
const element = (
<div>
<Clock index="0" />
<Clock index="1" />
<Clock date={new Date()} index="2" />
</div>
);
ReactDOM.render(element, document.getElementById('root'));
-
效果如图