v16.3.x

(UNSAFE) 三个生命周期

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

(新增) 两个生命周期

  • static getDerivedStateFromProps(nextProps, prevState)
  • getSnapshotBeforeUpdate

​ 虽然在16的版本里面还能使用旧的三个生命周期, 但是新的生命周期和旧的生命周期不能同时出现在同一个组件, 否则会报错.

为什么要改

​ react 打算在 v17 推出 Async Rendering, 提出一种可以被打断的生命周期, 而可以被打断的阶段是实际 dom 挂载之前, virtual dom 的构建阶段, 也就是要被去掉的三个生命周期. 生命周期一旦被打断,下次恢复的时候又会再跑一次之前的生命周期,因此这三个方法都不能保证只在组件更新state/props/ref的时候刷新一次了,所以这三个方法被标记为不安全.

新的生命周期

static getDerivedStateFromProps
  • 触发时间: mounting & updating

    v16.3.0: updating 中只有 new props 会触发该生命周期

    v.16.4之后: new props, setState, forceUpdate 都会触发该生命周期

  • 这是一个 static 方法, 意味着拿不到实例的 this

  • 每次接收新的 props 之后都会返回一个对象作为新的 state, 返回 null 则说明不需要更新 state

  • 配合 componentDidUpdate, 可以覆盖componentWillReceiveProps的所有用法

getSnapshotBeforeUpdate
  • 触发时间: 在 DOM updated 之前
  • 返回一个值, 作为componentDidUpdate的第三个参数
  • 配合componentDidUpdate, 可以覆盖 componentWillUpdate 的所有用法
  • 通常不需要此生命周期, 但在重新渲染期间手动保留滚动位置的情况下可能很有用

生命周期具体应用

  1. Updating state based on props

因为不能使用this.propsnextProps 进行对比, 所以可以额外写一个 state 来记录上一个 props

1
2
3
4
5
6
7
8
if (nextProps.currentRow !== prevState.lastRow) {
return {
...
lastRow: nextProps.currentRow,
};
}
// No state update necessary
return null;
  1. Fetching external data when props change
1
2
3
4
5
6
7
// old
componentWillReceiveProps(nextProps) {
if (nextProps.id !== this.props.id) {
this.setState({externalData: null});
this._loadAsyncData(nextProps.id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// new
static getDerivedStateFromProps(nextProps, prevState) {
// Store prevId in state so we can compare when props change.
if (nextProps.id !== prevState.prevId) {
return {
externalData: null,
prevId: nextProps.id,
};
}
// No state update necessary
return null;
}
componentDidUpdate(prevProps, prevState) {
if (this.state.externalData === null) {
this._loadAsyncData(this.props.id);
}
}

official context API

Note: 旧的 context API 会兼容 v16.x

文档

createRef API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyComponent extends React.Component {
constructor(props) {
super(props);

this.inputRef = React.createRef();
}

render() {
return <input type="text" ref={this.inputRef} />;
}

componentDidMount() {
this.inputRef.current.focus();
}
}

Note: 除了新的 createRef API 之外, 还将继续支持回调引用, 无需替换你的组件中的 callback refs

forwardRef API

高阶组件是在组件之间重用代码的常用方法, 高阶组件可以传递 props, 但是 refs 传递不了, 新的 forwardRef API 就解决了这个问题, 它能将 ref 转化为普通的 prop

文档

StrictMode Component

与Fragment一样, StrictMode不会呈现任何可见的UI. 它会为其后代激活其他检查和警告. StrictMode检查仅在开发模式下运行, 它们不影响生产构建. 文档

作用:

  • 识别 unsafe lifecycle
  • 关于string ref API 使用的警告
  • 检测意外的副作用

v16.4.x

Pointer Events

文档

bugfix for getDervedStateFromProps

在上面段落已经提过, v.16.4.0之后: mounting, new props, setState, forceUpdate 都会触发 getDervedStateFromProps

Note: 谨慎使用 derived state

v16.5.x

React Profiler

​ React 16.5 支持新的 profiler DevTools 插件, 这个插件使用 React 的experimental Profiler API 来收集每个组件渲染时间, 目的是为了找出你的 React App 的性能瓶颈。它将会和即将发布的 time slicing and suspense 特性完全兼容.

文档

Note: react-dom 16.5+ 和 react-native 0.57+