乐趣区

react组件生命周期函数

生命周期函数图谱

一、常用的生命周期函数

1.render()

render()
注意

(1) render() 方法是 class 组件中唯一 必须实现 的方法
(2) render() 函数应该为 纯函数

这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。如需与浏览器进行交互,请在 `componentDidMount()` 或其他生命周期方法中执行你的操作。保持 `render()` 为纯函数,可以使组件更容易思考。

(3) 如果 shouldComponentUpdate() 返回 false,则不会调用 render()

2.constructor()

在 React 组件挂载之前,会调用它的构造函数

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

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。通常,在 React 中,构造函数仅用于以下两种情况:

  • 通过给 this.state 赋值对象来初始化内部 state。
  • 为事件处理函数绑定实例
注意:

(1) 在 constructor() 函数中 不要调用 setState() 方法 。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state
(2) 要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 componentDidMount
(3) 避免将 props 的值复制给 state!这是一个常见的错误

constructor(props) {super(props);
 // 不要这样做
 this.state = {color: props.color};
}

3.componentDidMount()

componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用,依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,添加订阅等

componentDidMount()
注意:

(1) 你可以在 componentDidMount() 直接调用 setState()

它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 `render()` 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 `constructor()` 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理

4.componentDidUpdate()

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

componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate(prevProps) {
  // 典型用法(不要忘记比较 props):if (this.props.userID !== prevProps.userID) {this.fetchData(this.props.userID);
  }
}
注意:

(1) 你也可以在 componentDidUpdate() 直接调用 setState(),但请注意 它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props“镜像”给 state,请考虑直接使用 props。
(2) 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()

5.componentWillUnmount()

componentWillUnmount()

componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

注意:

(1) componentWillUnmount() 不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

二、不常用的生命周期函数

1.shouldComponentUpdate()

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

shouldComponentUpdate(nextProps, nextState)

如果 shouldComponentUpdate() 返回 false,则不会调用 UNSAFE_componentWillUpdate()componentDidUpdate()

注意:

(1) 此方法仅作为性能优化的方式存在,不要试图通过此方法阻止重新渲染,可以使用内置的 PureComponent 组件,PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性
(2) 不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能

2.static getDerivedStateFromProps()

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容

static getDerivedStateFromProps(props, state)
注意:

(1) 不管原因是什么,都会 在每次渲染前触发此方法。这与 UNSAFE_componentWillReceiveProps 形成对比,后者仅在父组件重新渲染时触发,而不是在内部调用 setState

3.getSnapshotBeforeUpdate()

getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()

getSnapshotBeforeUpdate(prevProps, prevState)

三、16.13 版本过时的生命周期函数

1.UNSAFE_componentWillMount()

UNSAFE_componentWillMount() 在挂载之前被调用。它在 render() 之前调用,因此在此方法中同步调用 setState() 不会触发额外渲染。通常,我们建议使用 constructor() 来初始化 state。

UNSAFE_componentWillMount()
注意:

(1) 避免在此方法中引入任何副作用或订阅。如遇此种情况,请改用 componentDidMount()
(2) 此方法是服务端渲染唯一会调用的生命周期函数

2.UNSAFE_componentWillReceiveProps()

UNSAFE_componentWillReceiveProps() 会在已挂载的组件接收新的 props 之前被调用。如果你需要更新状态以响应 prop 更改(例如,重置它),你可以比较 this.propsnextProps 并在此方法中使用 this.setState() 执行 state 转换

UNSAFE_componentWillReceiveProps(nextProps)
注意:

(1) 如果父组件导致组件重新渲染,即使 props 没有更改,也会调用此方法。如果只想处理更改,请确保进行当前值与变更值的比较

3.UNSAFE_componentWillUpdate()

当组件收到新的 props 或 state 时,会在渲染之前调用 UNSAFE_componentWillUpdate()。使用此作为在更新发生之前执行准备更新的机会。初始渲染不会调用此方法。

UNSAFE_componentWillUpdate(nextProps, nextState)
注意:

(1) 不能此方法中调用 this.setState()
(2) 此方法可以替换为 componentDidUpdate()。如果你在此方法中读取 DOM 信息(例如,为了保存滚动位置),则可以将此逻辑移至 getSnapshotBeforeUpdate()

四、其他 API

1.setState()

setState(updater, [callback])

setState() 并不总是立即更新组件。它会批量推迟更新。这使得在调用 setState() 后立即读取 this.state 成为了隐患。为了消除隐患,请使用 componentDidUpdate 或者 setState 的回调函数(setState(updater, callback)),这两种方式都可以保证在应用更新后触发。

this.setState((state, props) => {return {counter: state.counter + props.step};
});

2.forceUpdate()

component.forceUpdate(callback)

默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。
调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。

退出移动版