当前位置: 首页 > news >正文

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

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 <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

【未完待续】

相关文章:

  • 今年的LC3大会没了?
  • 戴姆勒与宝马抱团开发自动驾驶 新旧车企大战在即
  • TableStore多元索路由探微
  • JPress v2.0-rc.4 发布,修复插件安装卸载的若干问题
  • 002_python基础语录
  • redis事务和脚本
  • Spring源码分析(六)SpringAOP实例及标签的解析
  • Nodejs教程11:assert(断言)
  • use Google search engine
  • 【zookeeper源码】启动流程详解
  • Linux 搭建 Jenkins
  • 新技术到底靠不靠谱?在中国用一下就知道了
  • 设计模式 —— 建造者模式
  • OpenAI发布大型强化深度学习模拟器Neural MMO,AI适者生存择最优
  • 新手站长们看过来:白话ID
  • 【前端学习】-粗谈选择器
  • Android开源项目规范总结
  • co.js - 让异步代码同步化
  • gf框架之分页模块(五) - 自定义分页
  • github从入门到放弃(1)
  • Redash本地开发环境搭建
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • Windows Containers 大冒险: 容器网络
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 观察者模式实现非直接耦合
  • 记一次和乔布斯合作最难忘的经历
  • 前端技术周刊 2019-02-11 Serverless
  • 前端知识点整理(待续)
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 入口文件开始,分析Vue源码实现
  • 使用agvtool更改app version/build
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 微信开放平台全网发布【失败】的几点排查方法
  • 如何正确理解,内页权重高于首页?
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (pojstep1.1.2)2654(直叙式模拟)
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (Ruby)Ubuntu12.04安装Rails环境
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • .bat批处理(六):替换字符串中匹配的子串
  • .gitignore
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .NET和.COM和.CN域名区别
  • .NET微信公众号开发-2.0创建自定义菜单
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • [Android]Android P(9) WIFI学习笔记 - 扫描 (1)
  • [ASP.NET 控件实作 Day7] 设定工具箱的控件图标