React16 后的各功能点是多个版本陆陆续续迭代增长的,本篇文章的讲解是创建在16.6.0
版本上
本篇文章主旨在介绍 React16 以后版本中新增或修改的地方,因此对于 React16 以前版本的功能,本篇文章看成您已充分了解了,再也不赘述
从 React v16.0 ~ React v16.6 的更新概览(只涉及部分经常使用api):react
render
支持返回数组和字符串createContext
createRef
更新 getDerivedStateFromProps
api
memo
lazy
static contextType
static getDerivedStateFromError
Hooks数组
接下来将针对影响较大,使用频率较高的更新点逐一讲解。性能优化
咱们知道,对 React 组件的性能优化,shouldComponentUpdate
函数是很重要的一啪,因此 React 才会在 React.Component
的基础上增长了React.PureComponent
,可是对于非class类的纯函数写法,却无法增长这样的便捷处理。
对于这个问题,React16.6 增长了React.memo
这个高阶组件函数
通常使用方式:性能
const C = React.memo(props => { // xxx })
React.memo
的实现相似React.PureComponent
,因此它内部是对对象进行浅比较。React.memo
容许你自定义比较方法,以下:优化
// 函数的返回值为 true 时则更新组件,反之则不更新 const equalMethod = (prevProps, nextProps): boolean => { // 定义你的比较逻辑 } const C = React.memo(props => { // xxx }, equalMethod)
React生命周期分为三个阶段:挂载、更新、卸载,React16后又多了一个异常,咱们一一看下。this
constructor
static getDerivedStateFromProps
render
componentDidMount
render
和componentDidMount
较 React16 以前无变化。对于挂载过程,咱们着重看下constructor
、componentWillMount
和static getDerivedStateFromProps
。spa
props
给state
赋值,这样的话, state
的初始化能够提到constructor
外面处理constructor(props) { super(props); this.state = { x: 1, // y: props.y, // 避免这样作,后面咱们会讲应该怎样处理 } }
constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); }
可是,以上两件事放到constructor
外面处理会更简单些,以下:设计
class C extends React.Component { state = { x: 1 } handleClick = (e) => { // xxx } }
因此,React16 之后用到constructor
的场景会变少。
能够看到,componentWillMount
在 React16 中被“删掉”了(这样说实际上是有问题的,由于 React 并未真正删除该生命周期函数,只是告诫开发者,该函数在将来版本中会被废弃掉),那么问题就出现了,原先在这个生命周期中的作的事情,如今该放到哪里去作呢?
首先问本身一个问题,原先的时候都在这个生命周期里作什么?答案是大部分时候会在这里作 AJAX 请求,而后执行setState
从新渲染。
然而在componentWillMount
里作 AJAX 请求实在不是一个明智之举,由于对于同构项目中,componentWillMount
是会被调用的。
还有人会在这里面初始化state
,关于state
的初始化,请参看楼上小节。
综上所述,componentWillMount
其实原本没有什么主要做用,若是你的代码规范,去掉的话,不会对如今的项目产生什么影响。
上面咱们讲到,应避免使用props
给state
赋值,可是在 React16 前咱们都是这么作的,如今若是不让这么操做了,那该在哪里处理这块逻辑呢? React16 给出的答案就是 static getDerivedStateFromProps
。
挂载组件时,该静态方法会在render
前执行;更新组件时,该静态方法会在shouldComponentUpdate
前执行。
class C extends React.Component { state = { y: 0 } static getDerivedStateFromProps(props, state): State { if(props.y !== state.y) { return { y: props.y }; } } }
getDerivedStateFromProps
的返回值将做为setState
的参数,若是返回null,则不更新state,不能返回object 或 null 之外的值,不然会警告。
getDerivedStateFromProps
是一个静态方法,是拿不到实例this
的,因此开发者应该将该函数设计成纯函数。
这样,有没有发现componentWillReceiveProps
也就没有用武之地了?是的,React16 把它也“删掉”了(这样说实际上是有问题的,由于 react 并未真正删除该生命周期函数,只是告诫开发者,该函数在将来版本中会被废弃掉,建议使用更好的getSnapshotBeforeUpdate
或 getDerivedStateFromProps
)
static getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
componentDidUpdate
static getDerivedStateFromProps
前面已经介绍过了,而其余的几个生命周期函数与 React16 以前基本无异,因此这里主要介绍下getSnapshotBeforeUpdate
。
在 React 更新 DOM 以前调用,此时state
已更新;
返回值做为componentDidUpdate
的第3个参数;
通常用于获取render
以前的 DOM 数据
语法:
class C extends React.Component { getSnapshotBeforeUpdate (prevProps, prevState): Snapshot { } componentDidUpdate(prevProps, prevState, snapshot) { // snapshot 是从 getSnapshotBeforeUpdate 的返回值,默认是 null } }
getSnapshotBeforeUpdate
的使用场景通常是获取组建更新以前的滚动条位置。
componentWillUnmount
较以前无变化。
componentDidCatch
这个函数是 React16 新增的,用于捕获组件树的异常,若是render()
函数抛出错误,则会触发该函数。能够按照 try catch
来理解和使用,在可能出现错误的地方,使用封装好的包含 componentDidCatch
生命周期的组建包裹可能出错的组件。
class PotentialError extends React.Component { state = { error: false, } componentDidCatch(error, info) { console.error(info); this.setState({ error }); } render() { if (this.state.error) { return <h1>出错了,请打卡控制台查看详细错误!</h1>; } return this.props.children; } }
如:
const Demo = () => ( <PotentialError> <div>{{a: 1}}</div> </PotentialError> )
这样,Demo
组件即便直接使用对象做为子组件也不会报错了,由于被 PotentialError
接收了。
看看穿上新生命周期这身新衣服后的样子吧
import React from 'react' export default class MyComponent extends React.Component { constructor(props) { super(props); // 初始化state方式(1) this.state = { } } static defaultProps = { } // 初始化state方式(2) state = { } static getDerivedStateFromProps(props, state) { return state } componentDidCatch(error, info) { } render() { } componentDidMount() { } shouldComponentUpdate(nextProps, nextState) { } getSnapshotBeforeUpdate(prevProps, prevState) { } componentDidUpdate(prevProps, prevState, snapshot) { } componentWillUnmount() { } }
【未完待续】