本文转载自:众成翻译
译者:iOSDevLog
链接:https://www.zcfy.cc/article/3827
原文:https://www.fullstackreact.com/30-days-of-react/day-7/
原著PDF版本下载:下载超过300页的 PDF
注意:这篇文章是关于经典的React生命周期挂钩。
如果您想了解新的生命周期 API,请单击此处
今天,我们将看看我们可以用于React组件的一些最常见的生命周期钩子函数,我们将讨论为什么它们是有用的,什么时间应该用什么。
恭喜!我们已经在React的第一周结束了,我们已经覆盖了这么多的基础知识。我们刚刚完成了处理有状态的组件来跟踪组件的内部状态。今天,我们将暂停实施,并谈一下应用中的组件lives。也就是说,我们将讨论组件的生命周期。
由于React装载了我们的应用,它为我们提供了一些钩子,我们可以在组件生命周期的不同时间插入自己的功能。为了hook into到生命周期,我们需要在我们的组件上定义函数,每个钩子在适当的时候对其进行调用。让我们来看看第一个生命周期钩子:
componentWillMount() / componentDidMount()
当在应用程序的页面上定义组件时,我们不能依赖它在DOM中的可用性,因为我们正在定义虚拟节点。相反,我们必须等到组件本身真正安装到浏览器中。对于安装后需要运行的功能,我们可以定义两个不同的钩子(或函数)。一个是在组件即将装入页面之前调用的,另一个是在组件装入之后调用的。
What does mounting mean?
因为我们用React定义DOM树中节点的虚拟表示,所以实际上我们并没有定义DOM节点。相反,我们正在建立一个内存视图,React为我们维护和管理。当我们讨论挂载时,我们讨论的是将虚拟组件转换为实际的DOM元素的过程,这些元素通过React放置在DOM中。
这对于获取数据以填充组件之类的事情很有用。例如,假设我们想使用活动跟踪器来显示github事件。我们只想在数据本身将被呈现时加载这些事件。
回想一下,我们在活动列表中定义了内容组件:
class Content extends React.Component {
render() {
const {activities} = this.props; // ES6 destructuring
return (
<div className="content">
<div className="line"></div>
{/* Timeline item */}
{activities.map((activity) => (
<ActivityItem
activity={activity} />
))}
</div>
)
}
}
让我们更新Content 组件,向github.com events api发出请求,并使用响应来显示活动。 因此,我们需要更新对象的state 。
就像我们昨天做的那样,我们通过在构造函数中将 this.state
设置为一个对象来更新我们的组件为状态
class Content extends React.Component {
constructor(props) {
super(props);
this.state = {
activities: []
}
}
// ...
}
现在,当组件本身准备装载(或装载之后)时,我们将要发出一个HTTP请求。通过在我们的组件中定义函数 componentWillMount()
(或 componentDidMount()
),React将在DOM中装载该方法之前运行该方法。 这是我们添加 GET
请求的完美的地方。
让我们更新 content
组件,并请求github api。 由于我们只想显示一个小列表,我们来看最新的四个活动。
我们已经存储了一个github数据的静态JSON文件,我们将直接从源码(我们将在几天内使用AJAX请求)使用promises。 现在,让我们重点介绍如何使用新的数据实现更新组件:
class Content extends React.Component {
// ...
componentWillMount() {
this.setState({activities: data});
}
// ...
}
我们还要稍微更新 ActivityItem
组件,以反映新的 activity
对象结构。我们也在用 Moment.js
库将日期格式化为人类友好的字符串,例如 30 min ago
要将其包含在文件中,请将以下 script
标记添加到文档中
<script src="https://unpkg.com/moment@2.24.0/min/moment.min.js"></script>
class ActivityItem extends React.Component {
render() {
const { activity } = this.props;
return (
<div className='item'>
<div className={'avatar'}>
<img
alt='avatar'
src={activity.actor.avatar_url} />
</div>
<span className={'time'}>
{moment(activity.created_at).fromNow()}
</span>
<p>{activity.actor.display_login} {activity.payload.action}</p>
<div className={'right'}>
{activity.repo.name}
</div>
</div>
)
}
}
请注意,我们没有从我们的 Content
组件更改任何内容,它正常工作了。
componentWillUpdate() / componentDidUpdate()
有时我们会在更改实际呈现之前或之后更新我们组件的一些数据。 例如,假设当组件的属性更改时,我们要调用一个函数来设置渲染或调用一个函数集。componentWillUpdate()
方法是一个合理的钩子来处理我们的组件进行更改(只要我们不调用 this.setState()
来处理它,因为它会导致无限循环)。
由于我们真的不需要深入处理这个问题,所以我们不用担心在这里设置一个例子,但是很高兴知道它存在。 我们使用的一个更常见的生命周期钩子是 componentWillReceiveProps()
钩子。
componentWillReceiveProps()
当组件即将接收新的 props
时,React会调用一个方法。 这是当组件将要接收一组新的属性时将被调用的第一种方法。 定义这种方法是寻找特定 props
更新的好时机,因为它使我们有机会计算更改并更新组件的内部状态。
这时我们可以根据新属性更新我们的状态。
这里要注意的一点是,即使 componentWillReceiveProps()
方法被调用,props
的值可能没有更改。 总是检查prop值的变化是一个好主意。
例如,让我们添加一个刷新按钮到我们的活动列表,以便我们的用户可以请求重新请求github事件api。
我们将使用 componentWillReceiveProps()
钩子来要求组件重新加载它的数据。 由于我们的组件是有状态的,我们将要使用新数据刷新此状态,因此我们不能简单地更新组件中的 props
。 我们可以使用 componentWillReceiveProps()
方法来告诉我们要刷新的组件。
我们在我们的包含元素上添加一个按钮,该元素传递一个 requestRefresh
布尔属性来告诉 Content
组件刷新。
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {refreshing: false}
}
// Bound to the refresh button
refresh() {
this.setState({refreshing: true})
}
// Callback from the `Content` component
onComponentRefresh() {
this.setState({refreshing: false});
}
render() {
const {refreshing} = this.state;
return (
<div className='notificationsFrame'>
<div className='panel'>
<Header title="Github activity" />
{/* refreshing is the component's state */}
<Content
onComponentRefresh={this.onComponentRefresh.bind(this)}
requestRefresh={refreshing}
fetchData={fetchEvents} />
{/* A container for styling */}
<Footer>
<button onClick={this.refresh.bind(this)}>
<i className="fa fa-refresh" />
Refresh
</button>
</Footer>
</div>
</div>
)
}
}
<Footer />
请注意,我们有一个新元素显示元素的子元素。 这是一种允许我们围绕一些内容添加CSS类的模式。
class Footer extends React.Component {
render() {
return (
<div className='footer'>
{this.props.children}
</div>
)
}
}
使用这个新的 prop
(requestRefresh prop
),当我们的state
对象改变值时,我们可以更新activities
。
class Content extends React.Component {
constructor {
this.state = {
activities: [],
loading: false // <~ set loading to false
};
}
// ...
updateData() {
this.setState(
{
loading: false,
activities: data.sort(() => 0.5 - Math.random()).slice(0, 4)
},
this.props.onComponentRefresh
);
}
componentWillReceiveProps(nextProps) {
// Check to see if the requestRefresh prop has changed
if (nextProps.requestRefresh === true) {
this.setState({ loading: true }, this.updateData);
}
}
// ...
}
我们还要更新componentWillMount
方法来调用此this.updateData()
而不是this.setState
class Content extends React.Component {
// ...
componentDidMount() {
this.updateData();
}
// ...
}
这个演示使用来自JSON文件的静态数据,并在刷新时随机选择四个元素。这是为了模拟刷新而设置的。
componentWillUnmount()
在组件卸载之前,React将调用componentWillUnmount()
回调。 这是处理我们可能需要的任何清理事件的时候,例如清除超时,清除数据,断开Websockets等。
例如,我们上次工作使用我们的时钟组件,我们设置一个超时时间被称为每秒钟。 当组件准备卸载时,我们希望确保我们清除此超时,以便我们的JavaScript不会继续为不存在的组件运行超时。
回想一下,我们构建的 timer
组件看起来像这样:
import React from 'react'
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = this.getTime();
}
componentDidMount() {
this.setTimer();
}
setTimer() {
this.timeout = setTimeout(this.updateClock.bind(this), 1000);
}
updateClock() {
this.setState(this.getTime, this.setTimer);
}
getTime() {
const currentTime = new Date();
return {
hours: currentTime.getHours(),
minutes: currentTime.getMinutes(),
seconds: currentTime.getSeconds(),
ampm: currentTime.getHours() >= 12 ? 'pm' : 'am'
}
}
// ...
render() {
}
}
export default Clock
当我们的时钟将被卸载时,我们将要清除我们在组件的setTimer()
函数中创建的超时。 添加componentWillUnmount()
函数负责这个必要的清理。
class Clock extends React.Component {
// ...
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
// ...
}
这些是我们可以在React框架中进行交互的一些生命周期钩子。 当我们构建我们的应用程序时,我们将会很多地使用这些应用,所以熟悉它们的方法是一个好主意,它们是如何存在,以及如何挂钩组件的生命。
我们在这篇文章中介绍了一个新的概念,我们已经看到了:我们在一个要从子组件调用到它的父组件上添加了一个回调。 在下一节中,我们将介绍如何定义和记录组件的prop
API,以便在整个团队和应用中共享组件时使用。
本教程系列的完整源代码可以在 GitHub repo, 上找到,其中包含所有样式和代码示例。
如果在任何时候你感到困扰,有进一步的问题,请随时通过以下方式与我们联系:
在原文文章末尾评论这篇文章
发送电子邮件至 [email protected]
加入我们的 gitter room
发推文给我们 @fullstackreact
REACT.JS DOM 应用 移动 JAVASCRIPT
版权声明 本译文仅用于学习、研究和交流目的,欢迎非商业转载。转载请注明出处、译者和众成翻译的完整链接。
原文链接:全栈React: React 30天