博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React16时代,该用什么姿势写 React ?
阅读量:6172 次
发布时间:2019-06-21

本文共 4610 字,大约阅读时间需要 15 分钟。

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

图片描述

挂载

生命周期的执行顺序

  1. constructor
  2. static getDerivedStateFromProps
  3. render
  4. componentDidMount

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

constructor

  1. 初始化 state
    注意:应避免使用propsstate赋值,这样的话, 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

上面我们讲到,应避免使用propsstate赋值,但是在 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 并未真正删除该生命周期函数,只是告诫开发者,该函数在未来版本中会被废弃掉,建议使用更好的getSnapshotBeforeUpdategetDerivedStateFromProps

更新

生命周期函数的执行顺序

  1. static getDerivedStateFromProps
  2. shouldComponentUpdate
  3. render
  4. getSnapshotBeforeUpdate
  5. 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 

出错了,请打卡控制台查看详细错误!

; } return this.props.children; } }

如:

const Demo = () => (  
{
{a: 1}}
)

这样,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

【未完待续】

转载地址:http://cqtba.baihongyu.com/

你可能感兴趣的文章
eclipse 构建maven web工程
查看>>
237. Delete Node in a Linked List
查看>>
[转] webpack之plugin内部运行机制
查看>>
宽字节与多字节之间的转换
查看>>
SEO的重要性
查看>>
ASP.NET 运行时详解 揭开请求过程神秘面纱
查看>>
Oracle 索引的失效检查
查看>>
C语言第五次作业--数据类型
查看>>
系统架构师-基础到企业应用架构-业务逻辑层
查看>>
高手详解SQL性能优化十条建议
查看>>
修改 IntelliJ IDEA 默认配置路径
查看>>
《现在的泪,都是当年脑子进的水》读书笔记
查看>>
IOSday04 UIButton使用
查看>>
铁大好青年内部分组
查看>>
unity3D ——自带寻路Navmesh入门教程(一)(转)
查看>>
判断字符串是否为数字的函数
查看>>
[emuch.net]MatrixComputations(7-12)
查看>>
linux 命令 — 文件相关
查看>>
自己空闲的时候封装一下
查看>>
Datagard產生gap
查看>>