组件通信介绍
- 组件是独立且封闭的单元,默认情况下,只能使用组件自己的数据。
- 在组件化过程中,我们将一个完整的功能拆分成多个组件,以更好的完成整个应用的功能。而在这个过程中,多个组件之间不可能避免的要共享某些数据。
- 为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。这个过程就是组件通讯
组件的props
- 组件是封闭的,要接受外部数据应该通过props来实现
- props的作用: 接收传递给组件的数据
- 传递数据: 给组件标签添加属性
- 接受数据: 函数组件通过参数props接受数据,类组件通过this.props来接受数据
特点
- 可以给组件传递任意类型的数据(函数,数组,JSX...)
- props是只读的对象,只能读取属性的值,无法修改对象
- 注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数中获取到props!
组件通讯的三种方式
组件之间的通讯分为 3 种:
- 父组件 ——> 子组件
- 子组件 ——> 父组件
- 兄弟组件
父组件传递数据给子组件
- 父组件提供要传递的state数据
- 给子组件标签添加属性,值为state中的数据
- 子组件中通过props接受父组件中传递的数据
子组件传递数据给父组件
思路: 利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。
- 父组件提供一个回调函数(用于接受数据)
- 将该函数作为属性的值,传递给子组件
- 子组件通过props调用回调函数
- 将子组件的数据作为参数传递给回调函数
兄弟组件
- 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
- 思想:状态提升
- 公共父组件的职责: 1. 提供共享状态 2. 提供操作共享状态的方法
- 要通讯的子组件只需通过props接受状态或操作状态的方法
Context
思考:如何实现多层传递
- 处理方式: 使用props一层一层组件往下传递(繁琐)
- 更好的处理方式: 使用Context
作用: 跨组件传递数据(比如主题、语言等)
使用步骤
-
调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件
const { Provider, Consumer } = React.createContext()
-
使用Provider组件作为父节点
<Provider>
<div className="APP">
<Child1 />
</div>
</Provider>
- 设置value属性,表示要传递的数据
<Provider value="blue">
- 使用Consumer组件接受数据
<Consumer>
{data => <span>data参数表示接收到的数据--{data}</span>}
</Consumer>
总结
- 如果两个组件嵌套多层,可以使用Context实现组件通讯
- Context提供了两个组件:Provider和Consumer
- Provider组件:用来提供数据
- Consumer组件:用来消费数据
props其他知识点
children属性
- children属性:表示组件标签的子节点。当组件标签有子节点时,props就会有该属性
- children属性和普通的props一样,值可以是任意值(react元素,函数,组件)
props校验
对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据 如果传入的数据格式不对,可能会导致组件内部报错,关键问题:组件的使用者不知道明确的错误原因
- props校验:允许在创建组件的时候,就指定props的类型、格式
- 作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,增加组件的健壮性,例
App.propTypes = { colors: PropTypes.array }
使用步骤
- 安装包prop-types(yarn add prop-types/npm i props-types)
- 导入prop-types包
import PropTypes from 'prop-types'
- 使用
组件名.propTypes = {}
来给组件的props添加校验规则 - 校验规则通过PropTypes对象来指定
约束规则
- 常见类型:array、bool、func、number、object、string
- React元素类型:element
- 必填项:isRequired
- 特定结构的对象:shape({})
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
所有类型可查看 reactjs.org/docs/typech…
props的默认值
- 场景:分页组件——>每页显示条数
App.defaultProps = { pageSize: 10}
- 作用:给props设置默认值,在未传入props时生效
组件的生命周期
组件的生命周期概述
- 意义: 组件的生命周期有助于理解组件的运行方式、完成更复杂的组件功能、分析组件错误原因等。
- 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程。
- 生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数。
- 生命周期的作用:为开发人员在不同阶段操作组件提供了时期。
- 只有 类组件 才有生命周期。
生命周期的三个阶段
- 每个阶段的执行时机
- 每个阶段钩子函数的执行顺序
- 每个阶段钩子函数的作用
创建时(挂载阶段)
- 执行时机:组件创建时(页面加载时)
- 执行顺序:
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