React v16 生命周期函数详解:如何、什么时候使用它们(React 组件生命周期的修订和最新指南)

翻译自 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


Mounting - 组件的挂载

├── constructor()dom

├── static getDerivedStateFromProps异步

├── renderide

├── componentDidMount函数

constructor

若是您的组件是 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 是渲染前调用的最后一个方法

通常使用 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返回状态对象。

render

完成全部渲染的工做。它返回实际组件的 JSX,使用React时,将花费大部分时间在这里。

渲染的最多见用例:返回 JSX 组件。

componentDidMount

在第一次渲染组件以后,触发此方法。

若是须要加载数据,请在此处执行。 不要尝试在 constructor 中加载数据或渲染,缘由,react-interview-questions.

因为AJAX是异步的,因此没法保证在组件挂载以前 AJAX 请求完成解析。 若是确实如此,那就意味着你要在未挂载的组件上尝试 setState,这不只不起做用,并且 React 报错。 在componentDidMount中执行 AJAX 将保证有一个要更新的组件。

componentDidMount 触发时,组件已完成第一 render,因此能够进行一些操做:

  • 在刚刚渲染的 <canvas> 元素上进行绘制
  • 访问 DOM 节点
  • 添加事件侦听器

基本上,在这里你能够作全部依赖 DOM 的设置,并开始得到你须要的全部数据,例如

componentDidMount() {
    // 利用 ref 访问 dom 元素
    this.bricks = initializeGrid(this.grid.current);
    this.interval = setInterval(() => {
      // ajax 获取数据
      this.addBlocks();
    }, 2000);
  }
}
复制代码

总结: 调用 AJAX 以加载组件的数据。

Updating - 组件的更新

├── static getDerivedStateFromProps

├── shouldComponentUpdate()

├── render

├── getSnapshotBeforeUpdate

├── componentDidUpdate()

getDerivedStateFromProps

是的,再来一次。 如今,它更有用了。

若是您须要根据 props 来更新 state,能够经过 return 新的状态对象来完成该任务。

注,不建议依据 props 来处理 state,也就是说,只有逼不得已才使用该方法。 如下是一些例子:

  • 当 video 、audio 的 source 改变时,须要重置元素;
  • Server 资源更新后须要恢复 UI 元素;
  • 当内容改变时关闭相关元素。

即便有上述状况,一般也有更好的方法。 可是 getDerivedStateFromProps 能够状况变得更坏。

总结: getDerivedStateFromProps 通常用于 props 不足以支撑业务时,利用它来更新 state。

shouldComponentUpdate

典型的 React 教条,当一个组件收到新的 State 或 Props时,它应该更新。

但咱们的组件有点困惑,它不肯定是否要进行更新。

shouldComponentUpdate 方法的第一个参数为 nextProps,第二个参数为 nextState。shouldComponentUpdate 返回一个布尔值,用于控制组件是否更新。

shouldComponentUpdate 赋予咱们一项能力,只有在你关心的 props 改变时组件会才更新。

总结: 能够准确地控制组件从新渲染的时间,经常使用于优化 React,具体

render - 同上
getSnapshotBeforeUpdate

新添加的方法,触发时刻在 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。

componentDidUpdate

全部的改变都已经提交给 DOM。

componentDidUpdate 包含三个参数,以前的 props、state,以及 getSnapshotBeforeUpdate 的返回值,具体如上述例子。

总结: 对已经改变的 Dom 做出相关响应。

Unmounting

componentWillUnmount

组件快要结束了。

在组件注销以前,它会询问您是否有任何最后一刻的请求。

您能够在此处取消任何传出网络请求,或删除与该组件关联的全部事件侦听器。

基本上,清理任何事情都只涉及有问题的组件 - 当它消失时,它应该彻底消失。

总结: 清除事件监听、定时器等,防止内存泄漏。

Errors

getDerivedStateFromError

发生了一些异常。

它可以捕捉在他们的子组件树中任意地方的 JavaScript 错误,记录这些错误。当咱们要展现一个 error 页面时,能够利用它来完成。

static getDerivedStateFromError(error) {
  return { hasError: true };
}
复制代码

注意: 您必须返回更新的状态对象。 不要将此方法用于任何反作用。 而是使用下面的 componentDidCatch。

总结: 依据错误信息来修改组件的 state,同时展现出 error 页面。

componentDidCatch

与上面很是类似,由于它在子组件中发生错误时被触发。

与 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的生命周期钩子所适用的场景和具体使用方法。

相关文章
相关标签/搜索