【React扩展】2、PureComponent、ErrorBoundary、render props和组件通信方式总结

在这里插入图片描述

欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框架 React框架 React框架,中间穿插了一些基础知识的回顾
博客主页codeMak1r.小新的博客

本文目录

  • 1.组件优化PureComponent
    • Component的2个问题
    • 效率高的做法
    • 原因
    • 解决
    • 示例1:重写shouldComponentUpdate方法
    • 示例2:PureComponent
  • 2.错误边界ErrorBoundary
    • 理解
    • 特点
    • 使用方式
  • 3.render props
    • 如何向组件内部动态传入带内容的结构(标签)?
    • children props
    • render props
    • 示例
  • 4.组件通信方式总结
    • 组件间的关系
    • 几种通信方式
    • 比较好的搭配方式

本文被专栏【React–从基础到实战】收录

坚持创作✏️,一起学习,码出未来‍!
【React扩展】2、PureComponent、ErrorBoundary、render props和组件通信方式总结_第1张图片

1.组件优化PureComponent

Component的2个问题

  1. 只要执行setState(),即使不改变状态数据,组件也会重新render();

    this.setState({});
    // 不改变状态,此时也会重新render()
    
  2. 只要当前组件重新render(),就会自动重新render子组件

    即使子组件没有用到父组件的任何数据 ==> 效率低;

效率高的做法

只有当组件的state或者props数据发生改变时才重新render()

原因

Component中的shouldComponentUpdate()总是返回true

解决

  1. 重写shouldComponentUpdate()方法

    比较新旧state或者props数据,如果有变化才返回true,如果没有返回false

  2. 使用PureComponent

    PureComponent重写了shouldComponentUpdate(),只有state或者props数据有变化才返回true

    注意⚠️:

    只是进行state和props数据的浅比较,如果只是数据对象内部数据变了,返回false;

    不要直接修改state数据,而是要产生新数据

项目中一般使用PureComponent来优化。

示例1:重写shouldComponentUpdate方法

// 父组件this.setState({});但是没有修改数据,组件就不会render
shouldComponentUpdate(nextProps, nextState) {
  console.log(this.props, this.state)  //目前的props和state
  console.log(nextProps, nextState)  // 要变化的目标props和state
  if (this.state.xxx=== nextState.xxx) return false
  else return true
}

判断状态更新前后的同一数据的值是否相同

若相同,则shouldComponentUpdate返回false(不render)

若不同,则shouldComponentUpdate返回true(允许render)

示例2:PureComponent

import React, { PureComponent } from 'react'

export default class Parent extends PureComponent{}
class Child extends PureComponent{}

PureComponent内部重写了shouldComponentUpdate方法,不用我们自己手写。

我们再来看前面提到的PureComponent存在的问题:

PureComponent进行的是数据的浅比较,也就是说,在修改状态数据时,不可以

const obj = this.state
obj.carName = 'Porsche-911 GT3 RS'
this.setState(obj)

这样修改数据,只是对原state对象内的值做了修改,但是对象的引用地址没变!!

PureComponent看来,引用地址没变时,组件内部的shouldComponentUpdate返回false,也就不会重新render,数据更新就失败了。

正确的更新状态应该是:

this.setState({ carName: 'Porsche-911 GT3 RS' });

这样修改数据,就是用一个新对象{ carName: 'Porsche-911 GT3 RS' }替换了原来的state对象,数据的引用地址变化了,那么PureComponent组件内部的shouldComponentUpdate返回true,组件重新render,数据更新成功。

2.错误边界ErrorBoundary

理解

错误边界(ErrorBoundary):用来捕获后代组件错误,渲染出备用界面。

所谓的边界,也就是把错误控制在一定范围内。比如后端的数据返回的是undefined或者返回的数据类型出现错误,又或者是其他的一些不可控的、未知的错误出现时,在页面上直接显示报错信息显然是不对的。这个时候,我们就应该把错误控制在可控范围内,一旦错误超出可控范围,我们直接在页面中“安抚”一下用户,可以提示用户:“网络繁忙请稍后重试”这样的信息,直接甩锅给运营商!(doge)

比如,子组件中要展示的页面需要发送请求给服务器,使用后端返回的数据进行页面的展示。

那么,在数据无异常的时候,正常地展示正常的页面;

在数据出错的时候,告诉用户:网络繁忙请稍后重试!

在这种情况下我们就可以使用错误边界来解决。

错误边界一般是在容易发生错误的组件的父组件中处理。

特点

只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误。

错误边界需要将错误限制在发生错误的组件当中,不要让错误扩散到上层组件。

使用方式

getDerivedStateFromError配合componentDidCatch

state = {
  hasError: false //用于标识子组件是否产生错误
}
// 如果当前组件的子组件出现了任何报错,都会调用这个钩子
static getDerivedStateFromError(error) {
  console.log(error)
  return { hasError: true }
}

这样的话,渲染子组件时就可以这样:

{this.state.hasError ? <h2>当前网络不稳定,稍后重试...</h2> : <Child />}

如果子组件出现任何报错,都不会干扰到其他组件的渲染,而只是在子组件的位置显示一行字:当前网络不稳定,稍后重试…

【React扩展】2、PureComponent、ErrorBoundary、render props和组件通信方式总结_第2张图片
上面的代码配合componentDidCatch

export default class Parent extends Component {
  state = {
    hasError: '' //用于标识子组件是否产生错误
  }
  // 如果当前组件的子组件出现了任何报错,都会调用这个钩子
  static getDerivedStateFromError(error) {
    console.log(error)
    return { hasError: error }
  }
  // 如果组件在渲染的过程中,子组件出现了问题引发了错误,就会调用这个钩子
  componentDidCatch(error, info) {
    console.log(error, info)
    // 这里一般用来统计错误次数,反馈给服务器,用于告知服务器维护人员这里有bug。
  }

  render() {
    return (
      <div className='parent'>
        <h2>我是Parent组件</h2>
        {this.state.hasError ? <h2>当前网络不稳定,稍后重试...</h2> : <Child />}
      </div>
    )
  }
}

3.render props

如何向组件内部动态传入带内容的结构(标签)?

Vue中:

  1. 使用slot技术,也就是通过组件标签体传入结构

React中:

  1. 使用children props:通过组件标签体传入结构
  2. 使用render props:通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性

children props

<A>
	<B>xxxx</B>
</A>
{this.props.children}
问题:如果B组件需要A组件内的数据 ==> 做不到

render props

<A render={(data) => <C data={data}</C>}</A>
  A组件:{this.props.render(内部state数据)}
	C组件:读取A组件传入的数据显示 {this.props.data}

示例

比如,有一个Parent组件为父组件,A组件为子组件,B组件为孙组件。

【React扩展】2、PureComponent、ErrorBoundary、render props和组件通信方式总结_第3张图片

A组件自身有一个状态为name,值为tom。B组件如果要想使用A组件的状态的话,正常的做法是:

Parent组件:
class Parent extends Component {
  render() {
    return (
    	<div>
      	<A/>
      </div>
    )
  }
}
A组件:
class A extends Component {
  state = { name:'tom' }
  render() {
    return (
    	<div>
      	<B name={this.state.name}/>
      </div>
    )
  }
}

将子组件A的name属性通过props传递给孙组件B。

不过,我们还可以使用render props来完成:

Parent组件:
class Parent extends Component {
  render() {
    return (
    	<div>
      	{/* 2.接收name参数,再传给B */}	
      	<A render={(name) => <B name={name}/>} />
      </div>
    )
  }
}

A组件:
class A extends Component {
  state = { name:'tom' }
  render() {
    const { name } = this.state
    return (
    	<div>
      	{/* 1.把name通过this.props.render()传过去 */}
      	{this.props.render(name)}
      </div>
    )
  }
}

这样,B组件也可以使用到A组件的状态,name被保存在B组件的this.props.name上。

4.组件通信方式总结

组件间的关系

  1. 父子组件
  2. 兄弟组件(非嵌套组件)
  3. 祖孙组件(跨级组件)

几种通信方式

  1. props

    (1)children props

    (2)render props

  2. 消息订阅与发布

    PubSub、event等等

  3. 集中式管理

    redux、dva、mobx等等

  4. Context

    生产者-消费者模式

比较好的搭配方式

父子组件:props

兄弟组件:消息订阅-发布、集中式管理

祖孙组件(跨级组件):消息订阅-发布、集中式管理、Context(开发用的少,封装插件用的多)

你可能感兴趣的:(React--从基础到实战,react.js,javascript,前端)