React16时代,该用什么姿势写 React ?

栏目: 服务器 · 发布时间: 6年前

内容简介:React16 后的各功能点是多个版本陆陆续续迭代增加的,本篇文章的讲解是建立在本篇文章主旨在介绍 React16 之后版本中新增或修改的地方,所以对于 React16 之前版本的功能,本篇文章当作您已充分了解了,不再赘述从 React v16.0 ~ React v16.6 的更新概览(只涉及部分常用api):

React16 后的各功能点是多个版本陆陆续续迭代增加的,本篇文章的讲解是建立在 16.6.0 版本上

本篇文章主旨在介绍 React16 之后版本中新增或修改的地方,所以对于 React16 之前版本的功能,本篇文章当作您已充分了解了,不再赘述

更新概览

从 React v16.0 ~ React v16.6 的更新概览(只涉及部分常用api):

  • React v16.0
  1. render 支持返回数组和字符串
  2. 支持自定义 DOM 属性
  3. 减少文件体积
  • React v16.3
  1. createContext
  2. createRef、
  3. 生命周期函数的更新
  • React v16.4

更新 getDerivedStateFromProps

  • React v16.6
  1. memo
  2. lazy
  3. Suspense
  4. static contextType
  5. static getDerivedStateFromError()
  • React v16.7(~Q1 2019)

Hooks

接下来将针对影响较大,使用频率较高的更新点逐一讲解。

纯函数的PureComponent

我们知道,对 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后又多了一个异常,我们一一看下。

React16时代,该用什么姿势写 React ?

挂载

生命周期的执行顺序

constructor
static getDerivedStateFromProps
render
componentDidMount

rendercomponentDidMount 较 React16 之前无变化。对于挂载过程,我们着重看下 constructorcomponentWillMountstatic getDerivedStateFromProps

constructor

  1. 初始化 state

    注意:应避免使用props给state赋值,这样的话, state 的初始化可以提到constructor外面处理

constructor(props) {
  super(props);
  this.state = {
    x: 1,
    // y: props.y, // 避免这样做,后面我们会讲应该怎样处理
  }
}
  1. 给方法绑定this
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

可以看到, componentWillMount 在 react16 中被“删掉”了(这样说其实是有问题的,因为 react 并未真正删除该生命周期函数,只是告诫开发者,该函数在未来版本中会被废弃掉),那么问题就出现了,原先在这个生命周期中的做的事情,现在该放到哪里去做呢?

首先问自己一个问题,原先的时候都在这个生命周期里做什么?答案是大部分时候会在这里做AJAX请求,然后执行 setState 重新渲染。

然而在 componentWillMount 里做AJAX请求实在不是一个明智之举,因为对于同构项目中, componentWillMount 是会被调用的。

还有人会在这里面初始化 state ,关于 state 的初始化,请参看楼上小节。

综上所述, componentWillMount 其实本来没有什么主要作用,如果你的代码规范,去掉的话,不会对现在的项目产生什么影响。

static getDerivedStateFromProps

上面我们讲到,应避免使用props给state赋值,但是在 React16 前我们都是这么做的,现在如果不让这么操作了,那该在哪里处理这块逻辑呢? React16 给出的答案就是 static getDerivedStateFromProps ,挂载组件时,该静态方法会在 render 前执行。

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 并未真正删除该生命周期函数,只是告诫开发者,该函数在未来版本中会被废弃掉,建议使用更好的 getSnapshotBeforeUpdategetDerivedStateFromProps

更新

生命周期函数的执行顺序

static getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
componentDidUpdate

static getDerivedStateFromProps 前面已经介绍过了,而其他的几个生命周期函数与 React16 之前基本无异,所以这里主要介绍下 getSnapshotBeforeUpdate

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 接收了。

新生命周期的完整demo

看看穿上新生命周期这身新衣服后的样子吧

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() {

  }

}

Suspense

Hooks

time slicing

【未完待续】


以上所述就是小编给大家介绍的《React16时代,该用什么姿势写 React ?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Reality Is Broken

Reality Is Broken

Jane McGonigal / Penguin Press HC, The / 2011-1-20 / USD 26.95

Visionary game designer Jane McGonigal reveals how we can harness the power of games to solve real-world problems and boost global happiness. More than 174 million Americans are gamers, and......一起来看看 《Reality Is Broken》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具