React:完整的生命周期及方法

什么是生命周期

在具备许多组件的应用程序中,当组件被销毁时释放所占用的资源是很是重要的。html

组件从 被建立被销毁 的过程称为组件的生命周期。react

组件的生命周期可分红三个状态:ajax

  • Mounting(挂载时)
  • Updating(更新时)
  • Unmounting(卸载时)

组件的生命周期可分为三个阶段:api

  • Render: 用于计算当前的状态/更新信息,会根据产生的任务的优先级,安排任务的调度(schedule)
  • Pre-commit: commit 以前,能够获取当前 DOM 的快照(snap)
  • Commit: 把全部更新都 commit 到 DOM 树上

生命周期方法

图解

常见方法版

react-lifecycle-1.png ( 图片来源:projects.wojtekmaj.pl/react-lifec…浏览器

完整方法版

react-lifecycle.png

( 图片来源:projects.wojtekmaj.pl/react-lifec…安全

方法

- contructor

constructor(props);
复制代码

一般,在 React 中,构造函数仅用于如下两种状况:性能优化

  • 经过给 this.state 赋值对象来初始化内部 state。( 惟一能够直接修改 state 的地方)
  • 为事件处理函数绑定实例

constructor() 函数中不要调用 setState() 方法。markdown

constructor(props) {
  super(props);
  // 不要在这里调用 this.setState()
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}
复制代码

- getDerivedStateFromProps

static getDerivedStateFromProps(props, state)
复制代码

这个方法是 “如何用 props 初始化 state ” 的最佳实践。网络

⚠️ 注意,该方法在每次 render 前都会被调用。函数

此方法适用于罕见的用例(表单控件获取默认值)。当 state 是从 props 获取时,就必需要维护二者的一致性,这将会增长复杂度和 bug

- shouldComponentUpate

shouldComponentUpdate(nextProps, nextState);
复制代码

propsstate 发生变化时,shouldComponentUpdate() 会在渲染执行以前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。

此方法 仅做为性能优化 的方式而存在。它的工做通常能够由 PrueComponent 自动实现。

后续版本,React 可能会将 shouldComponentUpdate 仅视为提示,而且,当返回 false 时,仍可能致使组件从新渲染。

- render

render();
复制代码

用于描述 DOM 结构,组件中惟一必须实现的方法。

- getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState);
复制代码

能在组件发生更改以前从 DOM 中捕获一些信息(例如,滚动位置)。今生命周期方法的任何返回值将做为参数传递给 componentDidUpdate()

- componentDidMount

componentDidMount();
复制代码

在组件挂载后(插入 DOM 树中)当即调用。在这里能够安全操做 DOM 节点、发送ajax 请求(DOM 节点的初始化)或一些反作用的事情(订阅)

若是你在这里调用了 setState,它将触发额外渲染,虽然此渲染会发生在浏览器更新屏幕以前,但会致使性能问题。

- componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot);
复制代码

在更新后会被当即调用。首次渲染不会执行此方法。

⚠ 注意, 若是直接调用 setState(),它必须被包裹在一个条件语句里,不然会致使死循环。

- componentWillUnmount

componentWillUnmount();
复制代码

在组件卸载及销毁以前直接调用,作一些资源释放操做,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中建立的订阅等。

⚠️ 注意:不该调用 setState(),由于该组件将永远不会从新渲染。

演示

Clock

用官方的经典 Clock 组件,能够清楚的展现出常见生命周期方法的应用:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  componentDidUpdate() {
    console.log("component did update!");
  }

  tick() {
    this.setState({
      date: new Date(),
    });
  }

  render() {
    return (
      <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
    );
  }
}

ReactDOM.render(<Clock />, document.getElementById("root"));
复制代码

在组件第一次挂载时,设置一个定时器;同时,在组件卸载时,清除定时器。

state.date 发生改变时,会引起组件的从新渲染。

getSnapshotBeforeUpdate 实践

以特殊方式处理滚动位置的聊天线程:由于每一条新消息的置顶设定,没法让页面固定在某处,因此在每次更新前都须要计算调整滚动条的位置。

class ScrollList extends PureComponent {
  state = {
    messages: [],
  };
  getSnapshotBeforeUpdate() {
    return this.rootNode.scrollHeight;
  }

  componentDidUpdate(prevProps, prevState, prevScrollHeight) {
    const scrollTop = this.rootNode.scrollTop;
    if (scrollTop < 5) return;
    this.rootNode.scrollTop =
      scrollTop + (this.rootNode.scrollHeight - prevScrollHeight);
  }

  render() {
    return (
      <div className="scroll-list" ref={(n) => (this.rootNode = n)}> {this.state.messages.map((msg) => ( <div>{msg}</div> ))} </div>
    );
  }
}
复制代码

DOM 更新前,经过 getSnapshotBeforeUpdate 获取原来的元素内容高度( scrollHeight ),并做为第三个参数传给 componentDidUpdate

componentDidUpdate 中,经过添加元素内容高度差值( this.rootNode.scrollHeight - prevScrollHeight ),调整滚动条位置( scrollTop )。

参考资料

React 入门

相关文章
相关标签/搜索