翻译自 React 16 Lifecycle Methods: How and When to Use Them,做者:Scott Domeshtml
参考 React.Componentreact
概述:最近在学习 react v16.8.4,发现组件的生命周期发生了一些变化,原有的一些方法被废弃,因此看了官方API介绍,再结合上述文章,作个总结。ajax
publish:2019-03-27canvas
自从我写了关于 React 组件生命周期的第一篇文章以来,相关的钩子函数、API已经发生了重大变化。 一些生命周期方法已被弃用,并引入了一些新的方法。 因此是时候进行更新了!网络
因为此次生命周期 API 有点复杂,我将这些方法分为四个部分:安装(Mounting),更新(Updating),卸载(Unmounting)和错误(Error)。app
├── constructor()dom
├── static getDerivedStateFromProps异步
├── renderide
├── componentDidMount函数
若是您的组件是 Class Component,则调用的第一就是组件构造函数。 这不适用于 Functional Component。
相关构造函数多是以下形式
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
}
复制代码
构造函数的参数为 props,你能够利用 super
来传入。
在构造函数中,你能够初始化 state、设定默认值。甚至你能够依据 props 来建立 state。
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
counter: props.initialCounterValue,
};
}
}
复制代码
注意,如今构造函数是可选的,若是您的 Babel 设置支持 class fields,就能够像这样初始化状态:
class MyComponent extends Component {
state = {
counter: 0,
};
}
复制代码
这种方法是被你们所提倡的。 你仍然能够根据 props 建立 state:
class MyComponent extends Component {
state = {
counter: this.props.initialCounterValue,
};
}
复制代码
可是,若是须要使用 ref ,就仍须要构造函数。
class Grid extends Component {
constructor(props) {
super(props);
this.state = {
blocks: [],
};
// 在 constructor 中建立 ref
this.grid = React.createRef();
}
}
复制代码
咱们须要构造函数来调用 createRef,以建立对 HTMLElement 元素的引用。还可使用构造函数进行函数绑定,这也是可选的
class Grid extends Component {
constructor(props) {
super(props);
this.state = {
blocks: [],
};
// 1
this.handleChange.bind(this)
}
// 2 等同于 1
handleChange = () => {}
}
复制代码
constructor总结: 构造函数的最常法:设置 state,建立 ref 和方法绑定。
挂载时,getDerivedStateFromProps 是渲染前调用的最后一个方法
通常使用 getDerivedStateFromProps 能够根据初始道具使用它来设置状态。
static getDerivedStateFromProps(props, state) {
return { blocks: createBlocks(props.numberOfBlocks) };
}
// log {blocks: Array(20)}
console.log(this.state);
复制代码
上述代码中依据 props.numberOfBlocks 来初始化指望的 state(函数return为状态)。
注意: 咱们能够将此代码放在 constructor 中,与之相 getDerivedStateFromProps的优势是它更直观 - 它仅用于设置状态,而构造函数有多种用途。
总结: getDerivedStateFromProps 的最多见用例(在mount期间):根据初始props返回状态对象。
完成全部渲染的工做。它返回实际组件的 JSX,使用React时,将花费大部分时间在这里。
渲染的最多见用例:返回 JSX 组件。
在第一次渲染组件以后,触发此方法。
若是须要加载数据,请在此处执行。 不要尝试在 constructor 中加载数据或渲染,缘由,react-interview-questions.
因为AJAX是异步的,因此没法保证在组件挂载以前 AJAX 请求完成解析。 若是确实如此,那就意味着你要在未挂载的组件上尝试 setState,这不只不起做用,并且 React 报错。 在componentDidMount中执行 AJAX 将保证有一个要更新的组件。
componentDidMount 触发时,组件已完成第一 render,因此能够进行一些操做:
<canvas>
元素上进行绘制基本上,在这里你能够作全部依赖 DOM 的设置,并开始得到你须要的全部数据,例如
componentDidMount() {
// 利用 ref 访问 dom 元素
this.bricks = initializeGrid(this.grid.current);
this.interval = setInterval(() => {
// ajax 获取数据
this.addBlocks();
}, 2000);
}
}
复制代码
总结: 调用 AJAX 以加载组件的数据。
├── static getDerivedStateFromProps
├── render
是的,再来一次。 如今,它更有用了。
若是您须要根据 props 来更新 state,能够经过 return 新的状态对象来完成该任务。
注,不建议依据 props 来处理 state,也就是说,只有逼不得已才使用该方法。 如下是一些例子:
即便有上述状况,一般也有更好的方法。 可是 getDerivedStateFromProps 能够状况变得更坏。
总结: getDerivedStateFromProps 通常用于 props 不足以支撑业务时,利用它来更新 state。
shouldComponentUpdate
典型的 React 教条,当一个组件收到新的 State 或 Props时,它应该更新。
但咱们的组件有点困惑,它不肯定是否要进行更新。
shouldComponentUpdate 方法的第一个参数为 nextProps,第二个参数为 nextState。shouldComponentUpdate 返回一个布尔值,用于控制组件是否更新。
shouldComponentUpdate 赋予咱们一项能力,只有在你关心的 props 改变时组件会才更新。
总结: 能够准确地控制组件从新渲染的时间,经常使用于优化 React,具体。
新添加的方法,触发时刻在 render 以后,最新的渲染输出提交给 DOM 以前。
调用渲染和最后显示更改之间可能会有延迟, 若是你须要获取 DOM 改变以前的一些信息时,能够利用这个钩子函数。
从渲染到提交这个过程是异步的,因此若是在 componentWillUpdate 访问 DOM 信息,在 componentDidUpdate 使用时,该信息可能发生了修改,这一部分以官网的例子来讲明
class ScrollingList extends React.Component {
listRef = React.createRef();
getSnapshotBeforeUpdate(prevProps, prevState) {
// 若是在列表中添加新项目
// 获取列表的当前高度,以便咱们稍后调整滚动
if (prevProps.list.length < this.props.list.length) {
return this.listRef.current.scrollHeight;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 若是咱们 snapshot 的值不为空,说明添加了新项目
// 调整滚动,以便这些新项目不会将旧项目推出可视区域
if (snapshot !== null) {
this.listRef.current.scrollTop +=
this.listRef.current.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
复制代码
总结: 查看当前 DOM 的某些属性,并将该值传递给componentDidUpdat。
全部的改变都已经提交给 DOM。
componentDidUpdate 包含三个参数,以前的 props、state,以及 getSnapshotBeforeUpdate 的返回值,具体如上述例子。
总结: 对已经改变的 Dom 做出相关响应。
组件快要结束了。
在组件注销以前,它会询问您是否有任何最后一刻的请求。
您能够在此处取消任何传出网络请求,或删除与该组件关联的全部事件侦听器。
基本上,清理任何事情都只涉及有问题的组件 - 当它消失时,它应该彻底消失。
总结: 清除事件监听、定时器等,防止内存泄漏。
发生了一些异常。
它可以捕捉在他们的子组件树中任意地方的 JavaScript 错误,记录这些错误。当咱们要展现一个 error 页面时,能够利用它来完成。
static getDerivedStateFromError(error) {
return { hasError: true };
}
复制代码
注意: 您必须返回更新的状态对象。 不要将此方法用于任何反作用。 而是使用下面的 componentDidCatch。
总结: 依据错误信息来修改组件的 state,同时展现出 error 页面。
与上面很是类似,由于它在子组件中发生错误时被触发。
与 getDerivedStateFromError 区别在于不是为了响应错误而更新状态,能够执行任何反作用,例如记录错误。
componentDidCatch(error, info) {
sendErrorLog(error, info);
}
复制代码
注意: componentDidCatch 仅会捕获渲染/生命周期方法中的错误。 若是在单击处理程序中引起错误,则不会捕获它。
一般只在特殊的地方使用错误边界组件的 componentDidCatch。 这些组件包装子树的惟一目的是捕获和记录错误。
class ErrorBoundary extends Component {
state = { errorMessage: null };
static getDerivedStateFromError(error) {
return { errorMessage: error.message };
}
componentDidCatch(error, info) {
console.log(error, info);
}
render() {
if (this.state.errorMessage) {
return <h1>Oops! {this.state.errorMessage}</h1>;
}
return this.props.children;
}
}
复制代码
总结: 捕获、打印出错误信息。
以上是React v16的生命周期钩子所适用的场景和具体使用方法。