一、 React中组件通信主要分为:
- 父子组件通信
- 子父组件通信
- 非父子组件通信
- 跨组件通信
- 多组件状态共享
这里主要对上述前四种通信方式举例说明:
父子组件通信
父子组件通信
无论父组件传递是props还是state,子组件都是通过props接收
父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时候,子组件接收到的属性就会发生改变
//父组件
import React , {Component} from 'react';
import Son from './Son'
class Father extends Component{
//定义数据并传给子组件
constructor(){
super()
this.state = {
name:'father',
give:1000,
}
}
render(){
return (
<div>
<h3>这里是父组件</h3>
<hr/>
<Son {...this.state}></Son>
</div>
)
}
}
export default Father;
=========================================================================================
//子组件
import React , { Component } from 'react';
class Son extends Component{
render(){
return (
<div>
<h3>这里是Son 组件</h3>
<p>父组件传过来的内容: { this.props.name } 给Son {this.props.give} </p>
</div>
)
}
}
export default Son;
子父组件通信
父组件将自己的某个方法传递给子组件,在方法里可以做任意操作,比如可以更改状态,子组件通过this.props接收到父组件的方法后调用。通知父组件进行相应操作。
注意: 组件自己的状态组件自己更改
//父组件
import React , { Component,Fragment } from 'react';
import Son from './Son.js';
class Father extends Component {
constructor () {
super()
this.state={
name:'Son',
flag:false,
msg:''
}
}
giveMoney=(val)=>{
this.setState({
flag:!this.state.flag,
msg:val ,
})
}
render(){
return (
<Fragment>
<h3>这里是Father组件</h3>
<hr/>
<Son giveMoney={this.giveMoney}></Son>
<p> { this.state.flag ? this.state.msg:'' } </p>
</Fragment>
)
}
}
export default Father;
=============================================================================================
//子组件
import React ,{ Component , Fragment} from 'react';
class Son extends Component {
render(){
return (
<Fragment>
<h3>这里是Son</h3>
<button
// 事件传参需要在定义一个箭头函数,在函数内传参,否则会报错
onClick= { ()=>{this.props.giveMoney('给父亲2000元红包')} }
>发红包</button>
</Fragment>
)
}
}
export default Son;
非父子组件通信
通过ref链来实现,借助父组件实现两个非父子组件之间的融信
举个例子:实现 姐姐给弟弟红包,弟弟开心笑,----需要逻辑,姐姐通过方法,改变弟弟状态
//Son 子组件
import React ,{ Component,Fragment} from 'react';
class Son extends Component {
constructor(){
super()
this.state={
flag:false,//定义一条数据控制Son组件部分内容的显示状态
}
}
change=()=>{
this.setState({
flag :!this.state.flag,
})
}
render (){
return (
<Fragment>
{/* 将change 方法通过属性传递到父组件内 */}
<h3>这里是Son组件</h3>
{ this.state.flag && <p>弟弟开心的笑~~~(*^_^*)(*^_^*)(*^_^*)(*^_^*)(*^_^*)</p> }
</Fragment>
)
}
}
export default Son;
=========================================================================================
//Gril 子组件
import React ,{ Component,Fragment} from 'react';
class Gril extends Component {
render(){
return (
<Fragment>
<h3>这里是Grill组件</h3>
<button onClick = {this.props.handleClick} >给弟弟红包</button>
</Fragment>
)
}
}
export default Gril;
===========================================================================================
// Father父组件
import React ,{ Component,Fragment } from 'react';
import Son from './Son';
import Gril from './Gril';
class Father extends Component {
constructor(){
super()
console.log(this)//控制台打印Father组件
}
handleClick = () => {//定义一个方法触发Son组件的方法
this.refs.son.change ()
}
render(){
return (
<Fragment>
<h3>这里是Father组件</h3>
<hr/>
{/* 将调用son组件的方法,通过father组件的方法传给gril组件 */}
<Gril ref ="gril" handleClick = { this.handleClick } ></Gril>
<hr/>
{/* 在父组件内通过ref 绑定,父组件可以访问到子组件的方法*/}
<Son ref = "son"></Son>
</Fragment>
)
}
}
export default Father;
通过ref绑定后打印Father组件的this,可以查看到子组件的属性
除此之外,ref绑定也可以有另一种常用使用方式
import React ,{ Component,Fragment } from 'react';
import Son from './Son';
import Gril from './Gril';
class Father extends Component {
constructor(){
super()
console.log(this)//控制台打印Father组件
}
handleClick = () => {
this.son.change () // ref = { el => this.xxx = el } 绑定使用方法
}
render(){
return (
<Fragment>
<h3>这里是Father组件</h3>
<hr/>
{/* 将调用son组件的方法,通过father组件的方法传给gril组件 */}
<Gril ref ={ el => this.gril = el } handleClick = { this.handleClick } ></Gril>
<hr/>
{/* 直接将son属性通过this绑定在父组件的属性上,使用时直接通过this调用*/}
<Son ref ={ el => this.son = el }></Son>
</Fragment>
)
}
}
export default Father;
两种绑定实现结果相同,但是更推荐使用第二种方法,直接绑定为父组件的属性,看一下第二种绑定的结果,以及点击实现效果
跨组件通信
在react没有类似vue中的事件总线来解决这个问题,我们只能借助它们共同的父级组件来实现,将非父子关系装换成多维度的父子关系。react提供了context api来实现跨组件通信, React 16.3之后的contextapi较之前的好用。
- 使用流程:
创建上下文 React.createContext()
使用上下文包裹目标组件的父组件
<MoneyContext.Provider value = { money }>
<Father></Father>
</MoneyContext.Provider>
在目标组件中先定义一个静态属性 static contextType = MoneyContext
通过 this.context来使用数据
- 实例:
//实现grandfather直接给son200元钱
import React ,{ Component,Fragment} from 'react';
//创建上下文投影
const GiveMoney = React.createContext();
//子组件
class Son extends Component{
//在目标组件中定义一个静态属性static
static contextType = GiveMoney;
render(){
return (
<Fragment>
<h3>这里是Son组件</h3>
{/* 通过this.context 使用GrandFather组件传来的数据 */}
<p> 祖父给我{ this.context } 元钱</p>
</Fragment>
)
}
}
//父组件
class Father extends Component{
render(){
return (
<Fragment>
<h3>这里是Father组件</h3>
<hr/>
<Son></Son>
</Fragment>
)
}
}
class GrandFather extends Component {
constructor(){
super()
this.state={
msg:500
}
}
render(){
return (
<Fragment>
<h2>这里是GrandFather组件</h2>
<hr/>
{/* 使用上下文包裹目标组件的父组件,使用value属性传输数据 */}
<GiveMoney.Provider value = { this.state.msg }>
<Father></Father>
</GiveMoney.Provider>
</Fragment>
)
}
}
export default GrandFather;
二、HOC(高阶组件 — — Higher-Order Components)
Higher-Order Components就是一个函数,传给它一个组件,它返回一个新的组件。
高阶组件是一个函数
- 这个函数中接收一个参数,这个参数是一个组件
- 作用
- 让外层组件帮助我们完成任务,里层组件直接使用结果
- 实现一些属性或是方法的复用
- 两层组件的嵌套
- 外层组件我们称为: 容器组件 【 木耦组件 】
- 里层组件我们称为: UI组件
import React ,{ Component,Fragment } from 'react';
import Content from './Content';
import Wrapper from './Wrapper';
//定义高阶组件函数,参数为一个组件
const HOC = (HCompon) => {
//内部为组件嵌套组件
return class OutBox extends Component{
constructor(){
super()
this.state={
name:"张三",
age:null
}
}
change = ( ) => {
this.setState({
age:18,
})
}
render(){
return (
<Fragment>
{/* 通过属性结构解构赋值,内层UI组件继承外层组件的属性,状态及方法 */}
<HCompon {...this.props} {...this.state} change={this.change}></HCompon>
</Fragment>
)
}
}
}
//高阶组件的使用,将一个组件作为参数传入,返回一个新的组件
const HContent = HOC( Content );
const HWrapper = HOC( Wrapper );
class Container extends Component {
constructor () {
super()
this.state = {
msg: '今天周五了'
}
}
render (){
return (
<Fragment>
<h3>这里是高阶组件使用</h3>
<hr/>
{/* 通过解构将组件数据传给高阶组件外层组件 */}
<HContent { ...this.state }></HContent>
<HWrapper ></HWrapper>
</Fragment>
)
}
}
export default Container;
==============================================================================================
//Wrapper组件
import React ,{ Component,Fragment } from 'react';
class Wrapper extends Component {
render(){
return (
<Fragment>
<p>这里是wrapper组件 </p>
<button onClick = {this.props.change} >点击</button>
<p> name:{this.props.name} <br/>age:{this.props.age} </p>
</Fragment>
)
}
}
export default Wrapper;
==============================================================================================
//Content组件
import React ,{ Component, Fragment} from 'react';
class Content extends Component {
render(){
return (
<Fragment>
<p>这里是content组件</p>
<p> {this.props.msg} </p>
</Fragment>
)
}
}
export default Content;
从运行结果可以看出,子组件作为参数传入高阶组件函数,可以继承到外层组件的方法、属性、状态,可以 实现一些属性或是方法的复用。子组件通过this.props实现数据的使用。
以上均为个人理解