React中组件通信及高阶组件使用

一、 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就是一个函数,传给它一个组件,它返回一个新的组件。

高阶组件是一个函数

  • 这个函数中接收一个参数,这个参数是一个组件
  • 作用
    1. 让外层组件帮助我们完成任务,里层组件直接使用结果
    2. 实现一些属性或是方法的复用
  • 两层组件的嵌套
  • 外层组件我们称为: 容器组件 【 木耦组件 】
  • 里层组件我们称为: 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实现数据的使用。
在这里插入图片描述
以上均为个人理解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值