State
创建一个同名的ES6类,并从React.Component继承。
添加空渲染()方法。
将函数体移动到render()方法中。
在render()方法中使用此选项Props替换Props。
删除剩余的空函数声明。
通过调用ReactDOM Render()来修改我们要渲染的元素:
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
现在,Clock组件被定义为类,而不是函数。
每次更新组件时都会调用渲染方法,但只要<Clock/>在同一个DOM节点中渲染,就会只创建和使用Clock组件的一个类实例。这允许我们使用许多其他功能,如状态或生命周期方法。
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
放这个。props用这个替换日期。状态日期:
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Class 组件应该始终使用 props 参数来调用父类的构造函数。
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
将生命周期方法添加到类
在具有许多组件的应用程序中,在组件被破坏时释放所占用的资源是非常重要的。
当Clock组件首次呈现到DOM中时,为其设置计时器。这在React中称为“装载”。
同时,当删除DOM中的Clock组件时,应该清除计时器。这在React中称为“卸载”。
我们可以为类组件声明一些特殊方法,这些方法将在安装或卸载组件时执行:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
让我们快速总结一下发生了什么以及这些方法的调用顺序:
当<Clock/>传递给ReactDOM时,React将调用Clock组件的构造函数。因为Clock需要显示当前时间,所以它将使用包含当前时间的对象来初始化此状态我们稍后将更新状态。
然后React调用组件的render()方法。这就是React如何确定页面上应该显示的内容。然后React更新DOM以匹配Clock渲染的输出。
// Wrong
this.state.comment = 'Hello';
当Clock的输出插入DOM时,React将调用ComponentDidMount()生命周期方法。在该方法中,Clock组件请求浏览器设置一个计时器,以每秒调用组件的tick()方法一次。
// Correct
this.setState({comment: 'Hello'});
浏览器每秒调用一次tick()方法。在此方法中,Clock组件将通过调用setState()来计划UI更新。由于调用了setState(),React可以知道状态已经改变,然后再次调用render()方法来确定页面上应该显示什么。这一次,这一次。state日期不同,因此将呈现输出的更新时间。React还将相应地更新DOM。
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
从DOM中删除Clock组件后,React将调用componentWillUnmount()生命周期方法,计时器将停止。
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
为了解决这个问题,让setState()接收函数而不是对象。此函数使用最后一个状态作为第一个参数,当应用此更新时使用props作为第二个参数:
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
父组件和子组件都不能知道组件是有状态的还是无状态的,它们不关心它是函数组件还是类组件。
这就是为什么状态被称为局部状态或封装状态。除了拥有和设置它的组件之外,没有其他组件可以访问它。
组件可以选择将其状态作为道具传递给其子组件:
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
这通常被称为“自上而下”或“单向”数据流。任何状态始终属于特定组件,从该状态派生的任何数据或UI只能影响树中“低于”它们的组件。
如果你把一棵由组件组成的树想象成一个由道具组成的数据瀑布,那么每个组件的状态就像在任何时候向瀑布添加额外的水,但它只能向下流动。
为了证明每个组件都是真正独立的,我们可以创建一个呈现三个时钟的App组件:
unction App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);