文章目录
react 组件通讯与生命周期
1. 组件通讯方法
1.1 基本使用
-
因为组件有“独立”的特点,所以就会产生组件内和组件外两个概念
-
组件外向组件内传递数据,是通过组件属性
<组件名 属性={} />
的方式 -
组件内接受数据,是通过 props 接收传递进来的数据 (函数组件和类组件)
-
函数组件内通过参数 props 使用传递过来的数据,类组件内通过 this.props 使用传递进来的数据
使用组件传值
<Hello name="Jack" age={19} />
函数组件使用传递进来的数据
function Hello(props) { console.log(props) return ( <div>{props.name}</div> ) }
类组件使用传递进来的数据
class Hello extends React.Component { render() { return ( <div>{this.props.age}</div> ) } }
1.2 特点
-
可以给组件传递任意类型的数据
-
props 是只读的对象,只能读取属性的值,无法修改对象
-
注意:使用类组件时,如果写了构造函数,应该将 props 传递给 super(),否则无法在构造函数中获取到 this.props
class Hello extends React.Component { constructor(props) { // 推荐将props传递给父类构造函数 super(props) } render() { return <div>{this.props.age}</div> } }
2. 组件通讯的三种方式
- 父传子
- 子传父
- 非父子组件
2.1 父组件传递数据给子组件
-
父组件确定要传递给子组件的数据,通常是保存在 state 中的数据
-
给子组件标签添加属性,值为 state 中的数据
-
子组件中通过 props 接收父组件中传递的数据
父组件
class Parent extends React.Component { state = { lastName: '王' } render() { return ( <div> 传递数据给子组件:<Child name={this.state.lastName} /> </div> ) } }
子组件
function Child(props) { return <div>子组件接收到的数据:{props.lastName}</div> }
2.2 子组件传递数据给父组件
利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回掉函数的参数
-
父组件定义一个回调函数(用于接收数据)
-
父组件将回调函数作为属性的值,传递给子组件
-
子组件通过 props 获取到回调函数并调用,回调函数的参数,将作为数据传回到父组件中
父组件
class Parent extends React.Component { // 传递给子组件的函数 getChildMsg = (msg) => { console.log('接收到子组件数据', msg) } render() { return ( <div> 子组件:<Child sendMsg={this.getChildMsg} /> </div> ) } }
子组件
class Child extends React.Component { state = { childMsg: 'React’ } handleClick = () => { this.props.sendMsg(this.state.childMsg) } render() { return ( <button onClick={this.handleClick}>点我,给父组件传递数据</button> } ) }
2.3 非父子组件
- 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
- 状态提升
- 公共父组件职责: 1. 提供共享状态 2. 提供操作共享状态的方法
- 要通讯的子组件只需要通过 props 接收状态或操作状态的方法
3. Context
非父子组件传值需要借助于公共的父组件进行间接传递,比较繁琐。这里推荐使用 Context 这种跨组件传递数据的方式
使用步骤
-
调用
React.createContext()
创建 Provider 和 Comsumer 两个组件const { Provider, Comsumer } = React.createContext()
-
使用 Provider 组件作为父节点
<Provider> <div className="App"> <Child /> </div> </Provider>
-
设置 value 属性,表示要传递的数据
<Provider value="pink"> <div className="App"> <Child /> </div> </Provider>
-
调用 Comsumer 组件接收数据
<Comsumer> { data => <h1>接收到的数据:{ data }</h1> } </Comsumer>
总结
- 如果来年各个组件是多层嵌套可以使用 Context 实现组件通讯
- Context 提供了两个组件:Provider 和 Comsumer
- Provider 组件:用来提供数据
- Comsumer 组件:用来消费数据
4. props 深入
4.1 children 属性
-
children 属性:表示组件标签的子节点。当组件标签有子节点时,props 就会有该属性
-
children 属性与普通的 props 一样,值可以是任意值
function Hello(props) { return ( <div> 组件的子节点:{props.children} </div> ) } // 此时 children 中就是 “我是子节点” <Hello>我是子节点</Hello>
4.2 props 校验
-
对于组件来说,props 是外部数据的容器,无法保证组件使用者传入什么格式的数据
-
如果传入的数据格式不对,可能会导致组件内部报错
-
关键问题:除了语法报错信息之外没有额外错误提示
// 创建的组件 function App(props) { const arr = props.colors const list = arr.map((item, index) => <li key={index}>{item}</li>) return ( <ul>{list}</ul> ) } // 使用组件时 <App colors={19} />
-
props 校验:允许在创建组件的时候,就指定 props 的类型、格式等
-
作用:捕获使用组件时因为 props 导致的错误,给出明确的错误提示,增强组建的健壮性
App.propTypes = { colors: PropTypes.array }
使用步骤
-
安装 prop-types
npm i prop-types
-
导入 prop-types 包
-
使用
组件名.propTypes = {}
来给组件的 props 添加校验规则 -
校验规则用过 PropTypes 对象来指定
import PropTypes from 'prop-types' function App(props) { return ( <h1>Hi, {props.colors}</h1> ) } App.propTypes = { // 约定colors属性为array类型 // 如果类型不对,则报出明确错误,便于分析错误原因 colors: PropTypes.array }
约束规则
-
常见类型:number、 string、 array、bool、func、object
-
React元素类型:element
-
必填项:isRequired
-
特定结构的对象:shape({ })
// 常见类型 optionalFunc: PropTypes.func, // 必选 requiredFunc: PropTypes.func.isRequired, // 特定结构的对象 optionalObjectWithShape: PropTypes.shape({ color: PropTypes.string, fontSize: PropTypes.number })
4.3 props 的默认值
-
场景:分页组件—> 每页显示条数
-
作用:给 props 设置默认值,在未传入 props 时生效
function App(props) { return ( <div> 此处展示props的默认值:{props.pageSize} </div> ) } // 设置默认值 App.defaultProps = { pageSize: 10 } // 不传入pageSize属性 <App />
5. 组件的生命周期
5.1 组件生命周期概述
- 组件的生命周期:组件从被创建到挂载到页面中(显示),再到组件从页面中卸载(消失)的过程
- 生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数。
- 钩子函数的作用:为开发人员在不同阶段操作组件提供了时机。
- 理解了组件的生命周期就是理解了组件的运行方式,可以帮我们实现更复杂的组件和分析组件错误原因等
- 只有 类组件 才有生命周期。
5.2 生命周期的三个阶段
5.2.1 创建阶段(挂载)
-
执行时机
当组件实例被创建并插入到 DOM 中时
-
执行顺序
constructor() —> render() —> componentDidMount()
-
作用
钩子函数 触发时机 作用 constructor 创建组件时,最先执行 1. 初始化state 2. 为事件处理程序绑定this render 每次组件 state 改变触发 渲染 UI( 注意不能调用 setState() ) componentDidMount 组件挂载后 1. 发送网络请求2. DOM 操作
5.2.2 更新阶段
-
执行时机
- setSate() 2. forceUpdate() 3. 组件接收到新的 props (以上三者任意一种情况发生,触发组件重新渲染)
-
执行顺序
render() —> componentDidUpdate()
-
作用
钩子函数 触发时机 作用 render 每次组件渲染都会触发 渲染 UI componentDidUpdate 组件更新后(完成DOM渲染) 1.发送网络请求 2. DOM操作 注意:如果要setState() 必须放在一个if条件中
5.2.3 卸载阶段
-
执行时机
组件从页面消失
-
执行顺序
componentWillUnmount()
-
作用
钩子函数 触发时机 作用 componentWillUnmount 组件卸载(从页面中消失) 执行清理工作(比如:清理定时器,事件解绑等)