React
React组件间通信
- 父级向子级通信
- 子级向父级通信
- 同级组件间通信
- 跨组件通信 -context
在React.js 中, 组件间数据是自上向下流动(传递)的, 也就是一个父组件可以把它的 state/props通过 props 传参的方式传递给它的子组件, 但是子组件不能直接修改父组件的 state/props, 所以说 React中是单向数据流的.
如果子组件需要修改父组件的状态(数据), 是通过回调的方式来完成的.
父传子 props
props 传参的形式不仅可以传递数据, 还可以传递结构(即: 还可以通过props传递组件结构).
在
React
中,父组件给子组件传递数据, 最常用的是通过props
属性的方式传值. 通过在父组件中, 给子组件标签添加一个属性传值, 可以在子组件的props
中接收该值, 具体代码演示如下:
src/Parent.js
父组件import React, {Component} from 'react' import Children from './Children' class Parent extends Component { constructor(props) { super(props); this.state = { person:{ name:'Gene', } } } render() { return ( <div> <Children person={this.state.person}/> </div> ) } } export default Parent
src/Children.js
子组件代码import React, {Component} from 'react' class Children extends Component { render() { const {person} = this.props; return ( <div> <h2>hello, 我是children {person.name}!</h2> </div> ) } } export default Children
props.children 父传子
props.children介绍
每个组件都可以获取到props.children
. 它包含组件的开始标签和结束标签中间的内容, 我们同样可以依据这种方式给子组件中传递数据,通常我们用这种方式传递标签数据 .
src/parent.js 父组件代码import React, {PureComponent} from 'react' import Children from './Children' class Parent extends PureComponent { render() { return ( <div> <Children> <p>我是p1</p> <p>我是p2</p> <p>我是p3</p> </Children> </div> ) } } export default Parent
src/children .js 子组件代码
import React {PureComponent} from 'react' class Children extends PureComponent { render() { const {children} = this.props return ( <div> <h1>我是儿子组件</h1> {children} </div> ) } } export default Children
这种传参方式有一点儿类似于
Vue
中的slot插槽传参
,这样理解可能有点儿不准确, 暂且先这么理解
子传父 回调
子组件给父组件传递数据也是利用的是
props
传参的方式, 通过给子组件传入一个回调函数, 在子组件的props
中接收, 在子组件中调用该回调函数, 传入参数, 即可以在父组件中接收到子组件的数据. 具体演示代码如下:src/parent.js 父组件
import React, {Component} from 'react' import Children from './Children' class Parent extends Component { constructor(props) { super(props); this.getChildrenData=this.getChildrenData.bind(this) } getChildrenData(data){ console.log('%c接收子组件的数据 -->',"color:red",data); } render() { return ( <div> <Children getChildrenData={this.getChildrenData} /> </div> ) } } export default Parent
src/children.js 子组件
import React, {Component} from 'react' import Children from './Children' class Parent extends Component { constructor(props) { super(props); this.getChildrenData=this.getChildrenData.bind(this) } getChildrenData(data){ console.log('%c接收子组件的数据 -->',"color:red",data); } render() { return ( <div> <Children getChildrenData={this.getChildrenData} /> </div> ) } } export default Parent
跨组件通信 context
当组件的嵌套太深, 通过
props
层层传参的方式会比较麻烦, 此时我们可以考虑使用context
的方式传参.
context
一般不建议在项目中直接使用, 这种方式一般是给第三方的api
来使用的,比如redux
,如果不借助于第三方的库, 通过
context
方式通信也比较麻烦, 故我们此处不再贴详细代码, 如想了解, 详见官网描述注意 在使用不熟练时, 最好不要在项目中使用
context
,context
一般给第三方库使用.
React组件的生命周期
所谓的生命周期是指某个事物从开始到结束的各个阶段, 当然在React.js 中指的是组件从创建到销毁的过程, React.js在这个过程中的不同阶段调用的函数, 通过这些函数, 我们可以更加精确的对组件进行控制, .
React的生命周期演变
React 16.3 之前
- 挂载阶段
- constructor - componentWillMount - render - componentDidMount
- 更新阶段
#1. 父组件更新引起子组件更新 - componentWillReceiveProps(nextProps) - shouldComponentUpdate(nextProps, nextState) - componentWillUpdate(nextProps, nextState) - render - componentDidUpdate(prevProps, prevState) #2. 组件自身更新 - shouldComponentUpdate - componentWillUpdate - render - componentDidUpdate
- 挂载/销毁阶段
- componentWillUnmount
React16.3 之后
- 挂载阶段
- constructor - static getDerivedStateFromProps(props, state) - 注意: 在静态生命周期函数里没有this,要注意this问题 - render - componentDidMount
- 更新阶段
#1. 父组件更新引起子组件更新 - static getDerivedStateFromProps(props, state) - shouldComponentUpdate() - componentWillUpdate() - render() - getSnapshotBeforeUpdate() - componentDidUpdate() #2. 组件自身更新 - shouldComponentUpdate() - componentWillUpdate() - render() - getSnapshotBeforeUpdate() - componentDidUpdate()
- 卸载阶段
- componentWillUnmount
- 错误处理
- static getDerivedStateFromError() - componentDidCatch(error, info)
将来生命周期替代方法
useEffect() 副作用 (用来替代先行生命周期)
生命周期函数作用详解
constructor(props)
constructor
是类的构造函数, 也是组件初始化函数, 一般情况下, 我们会在这个阶段做一些初始化的工作
- 初始化 state
- 处理事件绑定函数的
this
render()
render
方法是Class
组件必须 实现的一个方法.
static getDerivedStateFromProps(props,state)
该方法会在
render
方法之前调用, 无论是挂载阶段还是更新阶段, 它的存在只有一个目的: 让组件在props
变化时更新state
componentDidMount()
在组件挂载后(render的内容插入 DOM树中)调用, 通常这个阶段, 我们可以
- 操作 DOM 节点
- 发送请求
getSnapshotBeforeUpdata(prevProps,prevState)
该方法在
render()
之后, 但是在输出到DOM
之前执行, 用来获取渲染之前的文档快照, 当我们想在当前一次更新前获取上次的DOM
状态, 可以在这里进行处理, 该函数的返回值将作为参数传递给下个声明周期函数componentDidUpdate
但是该函数并不常用
componentDidUpdate()
该函数会在
DOM
更新后立即调用, 首次渲染不会调用该方法 , 我们可以在这个函数中对渲染后的DOM
进行操作
componentWillUnmount()
该方法会在组件卸载及销毁前调用, 我们可以在这里做一些清理工作, 如: 组件内的定时器, 未完成的请求等.
错误处理
- 错误捕获, 不捕获事件中的错误
- 在父级组件中捕获子组件中的错误.
当渲染过程, 生命周期, 或子组件的构造函数中抛出错误时, 会调用如下方法:
- static getDerivedStateFromError()
- componentDidCatch()
static getDerivedStateFromError()
该方法用来获取子组件抛出的错误,返回值是一个对象,该对象被存储在 state 中,在后续的 render 方法中就可以根据这个对象的值来进行处理,如:显示不同的 UI
static getDerivedStateFromError(error)
**componentDidCatch() ** // 将来版本会有变化
该方法与 getDerivedStateFromError() 类似,但是也有不同的地方:
- 该方法会有一个记录详细错误堆栈信息的 info 参数
- 该方法可以执行一些额外的操作:打印错误、上报错误信息……
componentDidCatch(error, info)