0
点赞
收藏
分享

微信扫一扫

《React扩展知识二》PureComponent / render props / Error boundary /组件通信方式总结

像小强一样活着 2022-08-13 阅读 44

前言

在这里插入图片描述

文章目录

1. 组件优化

Component的2个问题

效率高的做法

原因

重写shouldComponentUpdate()方法

export default class Parent extends Component {

  state = { carName: '奔驰' }

  changeCar = () => {
    this.setState({})
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log(this.props, this.state)  //目前的props和state
    console.log(nextProps, nextState) //接下来要变化的目标props,目标state
    if (this.state.carName === nextState.carName) return false
    else return true
  }

  render() {
    console.log('parent--render')
    return (
      <div className='parent'>
        <h3>我是Parent组件</h3>
        <span>我的车名字是:{this.state.carName}</span><br />
        <button onClick={this.changeCar}>点我换车</button>
      </div>
    )
  }
}

效果
在这里插入图片描述

问题2和问题1一样重写shouldComponentUpdate()方法

import React, { Component } from 'react'
import './index.css'

export default class Parent extends Component {
  state = { carName: '奔驰' }

  changeCar = () => {
    this.setState({ carName: '宝马' })
  }

  shouldComponentUpdate(nextProps, nextState) {
    // console.log(this.props, this.state)  //目前的props和state
    // console.log(nextProps, nextState) //接下来要变化的目标props,目标state
    if (this.state.carName === nextState.carName) return false
    else return true
  }

  render() {
    console.log('parent--render')
    return (
      <div className='parent'>
        <h3>我是Parent组件</h3>
        <span>我的车名字是:{this.state.carName}</span><br />
        <button onClick={this.changeCar}>点我换车</button>
        <Child carName='奥拓' />
      </div>
    )
  }
}

class Child extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    console.log(this.props, this.state)  //目前的props和state
    console.log(nextProps, nextState) //接下来要变化的目标props,目标state
    if (this.props.carName === nextProps.carName) return false
    else return true
  }

  render() {
    console.log('child--render')
    return (
      <div className='child'>
        <h3>我是Child组件</h3>
        <span>我接到的车是:{this.props.carName}</span>
      </div>
    )
  }
}

效果
在这里插入图片描述

使用PureComponent

当state状态里有多组数据,那么shouldComponentUpdate()里就要进行多个判断,这样显然在真正开发里是不可行的。所以我们可以不用手动写shouldComponentUpdate()方法, 使用PureComponent, 可以重写shouldComponentUpdate()里的逻辑, 只有state或props数据有变化才返回true。(项目中一般使用PureComponent来优化)

import React, { PureComponent } from 'react'
...
export default class Parent extends PureComponent{}
...
class Child extends PureComponent{}
...

注意! 🔥 PureComponent只是进行state和props数据的浅比较,如果只是数据对象内部数据变了,返回false。 不要直接修改state数据, 而是要产生新数据

//错误写法
const obj = this.state
obj.carName = '宝马'
this.setState(obj) 
//正确写法
this.setState({ carName: '宝马' })

2. render props

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

Vue中:

<A>
  <B/>
</A>

React中:

children props

<A>
  <B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到 
export default class Parent extends Component {
  render() {
    return (
      <div className='parent'>
        <h3>我是parent组件</h3>
        <A>
          <B />
        </A>
      </div>
    )
  }
}

class A extends Component {
  render() {
    console.log(this.props)
    return (
      <div className='a'>
        <h3>我是A组件</h3>
        {this.props.children}
      </div>
    )
  }
}

class B extends Component {
  render() {
    return (
      <div className='b'>
        <h3>我是B组件</h3>
      </div>
    )
  }
}

效果

在这里插入图片描述

render props

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

如果在children props写法的基础上, 若要将A组件state身上的name属性传给B组件, 我们就需要使用render props来写:

export default class Parent extends Component {
  render() {
    return (
      <div className='parent'>
        <h3>我是parent组件</h3>
        <A render={(name) => <B name={name} />} />
      </div>
    )
  }
}

class A extends Component {
  state = { name: 'jack' }
  render() {
    console.log(this.props)
    const { name } = this.state
    return (
      <div className='a'>
        <h3>我是A组件</h3>
        {this.props.render(name)}
      </div>
    )
  }
}

class B extends Component {
  render() {
    return (
      <div className='b'>
        <h3>我是B组件,{this.props.name}</h3>
      </div>
    )
  }
}

效果

在这里插入图片描述

3. 错误边界Error boundary

理解

错误边界(Error boundary):把错误控制在一定范围内,比如后端返回来的数据类型出错,或者一些其他的错误,我们可以在界面中提示用户一些“网络繁忙请稍后重试”信息,错误边界Error boundary就是用来捕获后代组件错误,渲染出备用页面。

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

特点

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

使用方式

getDerivedStateFromError配合componentDidCatch

export default class Parent extends Component {
  state = {
    hasError: '' //用于标识子组件是否产生错误
  }

  // 如果Parent组件的子组件出现了任何的报错,都会调用这个钩子函数,调用的时候传入error错误信息
  static getDerivedStateFromError(error) {
    console.log(error)
    return { hasError: error }// 返回新的state
  }

  render() {
    return (
      <div>
        <h2>我是Parent组件</h2>
        {this.state.hasError ? <h2>当前网络不稳定,请稍后再试</h2> : <Child />}
      </div>
    )
  }
}
// 如果组件在渲染的整个过程中,由于子组件出现了问题,引发一些错误,
//就会调用此函数,用来统计错误,反馈给服务器,用于通知编码人员进行bug的解决
componentDidCatch(error, info) {
  // 统计页面的错误。发送请求发送到后台去
    console.log(error, info);
}

效果

在这里插入图片描述

4. 组件通信方式总结

组件间的关系

  • 父子组件
  • 兄弟组件(非嵌套组件)
  • 祖孙组件(跨级组件)

几种通信方式

  1. props:
    • children props
    • render props
  2. 消息订阅-发布:
    • pubs-sub、event等等
  3. 集中式状态管理:
    • redux、dva等等
  4. conText:
    • 生产者-消费者模式

比较好的搭配方式

举报

相关推荐

0 条评论