React 组件通讯(学习笔记)

472 阅读5分钟

组件通信介绍

  • 组件是独立且封闭的单元,默认情况下,只能使用组件自己的数据。
  • 在组件化过程中,我们将一个完整的功能拆分成多个组件,以更好的完成整个应用的功能。而在这个过程中,多个组件之间不可能避免的要共享某些数据
  • 为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。这个过程就是组件通讯

组件的props

  • 组件是封闭的,要接受外部数据应该通过props来实现
  • props的作用: 接收传递给组件的数据
  • 传递数据: 给组件标签添加属性
  • 接受数据: 函数组件通过参数props接受数据,类组件通过this.props来接受数据

特点

  1. 可以给组件传递任意类型的数据(函数,数组,JSX...)
  2. props是只读的对象,只能读取属性的值,无法修改对象
  3. 注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数中获取到props!

组件通讯的三种方式

组件之间的通讯分为 3 种:

  1. 父组件 ——> 子组件
  2. 子组件 ——> 父组件
  3. 兄弟组件

父组件传递数据给子组件

  1. 父组件提供要传递的state数据
  2. 给子组件标签添加属性,值为state中的数据
  3. 子组件中通过props接受父组件中传递的数据

子组件传递数据给父组件

思路: 利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。

  1. 父组件提供一个回调函数(用于接受数据)
  2. 将该函数作为属性的值,传递给子组件
  3. 子组件通过props调用回调函数
  4. 将子组件的数据作为参数传递给回调函数

兄弟组件

  • 共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
  • 思想:状态提升
  • 公共父组件的职责: 1. 提供共享状态 2. 提供操作共享状态的方法
  • 要通讯的子组件只需通过props接受状态或操作状态的方法

Context

思考:如何实现多层传递

  • 处理方式: 使用props一层一层组件往下传递(繁琐)
  • 更好的处理方式: 使用Context
    作用: 跨组件传递数据(比如主题、语言等)

使用步骤

  1. 调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件
    const { Provider, Consumer } = React.createContext()

  2. 使用Provider组件作为父节点

<Provider>
   <div className="APP">
      <Child1 />
   </div>
</Provider>
  1. 设置value属性,表示要传递的数据
    <Provider value="blue">
  2. 使用Consumer组件接受数据
<Consumer>
   {data => <span>data参数表示接收到的数据--{data}</span>}
</Consumer>

总结

  1. 如果两个组件嵌套多层,可以使用Context实现组件通讯
  2. Context提供了两个组件:Provider和Consumer
  3. Provider组件:用来提供数据
  4. Consumer组件:用来消费数据

props其他知识点

children属性

  • children属性:表示组件标签的子节点。当组件标签有子节点时,props就会有该属性
  • children属性和普通的props一样,值可以是任意值(react元素,函数,组件)

props校验

对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据 如果传入的数据格式不对,可能会导致组件内部报错,关键问题:组件的使用者不知道明确的错误原因

  • props校验:允许在创建组件的时候,就指定props的类型、格式
  • 作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,增加组件的健壮性,例App.propTypes = { colors: PropTypes.array }
使用步骤
  1. 安装包prop-types(yarn add prop-types/npm i props-types)
  2. 导入prop-types包 import PropTypes from 'prop-types'
  3. 使用组件名.propTypes = {}来给组件的props添加校验规则
  4. 校验规则通过PropTypes对象来指定
约束规则
  1. 常见类型:array、bool、func、number、object、string
  2. React元素类型:element
  3. 必填项:isRequired
  4. 特定结构的对象:shape({})
optionalObjectWithShape: PropTypes.shape({
   color: PropTypes.string,
   fontSize: PropTypes.number
})

所有类型可查看 reactjs.org/docs/typech…

props的默认值
  • 场景:分页组件——>每页显示条数 App.defaultProps = { pageSize: 10}
  • 作用:给props设置默认值,在未传入props时生效

组件的生命周期

组件的生命周期概述

  • 意义: 组件的生命周期有助于理解组件的运行方式、完成更复杂的组件功能、分析组件错误原因等。
  • 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程。
  • 生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数。
  • 生命周期的作用:为开发人员在不同阶段操作组件提供了时期。
  • 只有 类组件 才有生命周期。

生命周期的三个阶段

  1. 每个阶段的执行时机
  2. 每个阶段钩子函数的执行顺序
  3. 每个阶段钩子函数的作用

创建时(挂载阶段)

  • 执行时机:组件创建时(页面加载时)
  • 执行顺序:
graph LR
Constructor --> Render --> ComponentDidMount
钩子函数触发时机作用
constructor创建组件时,最先执行1.初始化state
2.为事件处理程序绑定this
render每次组件渲染都会触发渲染UI(注意:不能调用setState())
componentDidMount组件挂载(完成DOM渲染)后1.发送网络请求
2.DOM操作

更新时(更新阶段)

  • 执行时机:1.setState() 2.forceUpdate() 3.组件接收到新的props
  • 说明:以上三者任意一种变化,组件就会重新渲染
  • 执行顺序:
graph LR
Render --> ComponentDidUpdate
钩子函数触发时机作用
render每次组件渲染都会触发渲染UI(注意:不能调用setState())
componentDidUpdate组件更新(完成DOM渲染)后1.发送网络请求
2.DOM操作
3.注意:如果要setState()必须放在一个if条件中
比较更新前后的props是否相同
conponentDidUpdate(prevProps){
   if(prevProps.count !== this.props.count) {
      this.setState({})
}

卸载时(卸载阶段)

  • 执行时机:组件从页面中消失 | 钩子函数 | 触发时机 | 作用 | | ----- | ----- | -----| | componentWillUnmount | 组件卸载(从页面中消失) | 执行清理工作(比如:清理定时器等)|

不常用钩子函数介绍

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate
  • shouldComponentUpdate