React组件通信

组件通信的意义

组件是独立且封闭的单元,默认情况下组件只能使用自己的数据(state)
组件化开发的过程中,完整的功能会拆分为多个组件,在这个过程中不可避免的需要互相传递一些数据
为了能让组件之间可以进行相互沟通,数据传递,这个过程就是组件通信

分类:

  1. 父子关系(最重要)
  2. 兄弟关系(自定义事件模式产生技术方法eventBus/通过共同的父组件通信)
  3. 其他关系(mobx/redux/基于hook的方案)

父传子

在这里插入图片描述

实现步骤:

  1. 父组件提供要传输的数据state
  2. 给子组件标签添加属性,值为state中的数据
  3. 子组件通过props接收父组件传过来的数据
    1. 类组件通过this.props获取props对象
    2. 函数式组件直接通过参数获取props对象

举例:

子组件获取父组件的数据:

import React from 'react';

//App父组件 Son子组件

//函数式组件的Son
function SonF(props){
    //props是一个对象 里边存着父组件传入的所有数据
    return(
        <div>我是函数子组件,{props.msg}</div>
    )
}

//类组件的Son
class SonC extends React.Component{
    render(){
        //类组件必须通过this关键词来获取,这里的props是固定的
        return(
            <div>我是类子组件{this.props.msg}</div>
        )
    }
}

//父组件
class App extends React.Component{
    //准备数据
    state = {
        message:'this is message'
    }
    render(){
        return(
            <div>
                {/* 在子组件身上绑定属性 属性名可以自定义 保持语义化 */}
                <SonF msg={this.state.message} />
                <SonC msg={this.state.message}/>
            </div>
        )
    }
}
export default App;

结果如图:
在这里插入图片描述

对props进行说明

  1. props是只读对象(readonly)

根据单向数据流(单向往下传,不能修改)的要求,子组件只能读取props中的数据,不能进行修改。

this.props.msg = 'new msg' //这是不可以的 不可以直接修改
  1. props可以传递任意数据

数字,字符串,布尔值,数组,对象,函数,JSX(一块模板)

举例:

import React from 'react';

//函数式组件的Son
function Son(props){
    console.log(props)
    //props是一个对象 里边存着父组件传入的所有数据
    return(
        <div>
            {/* 传递数组 */}
            {props.list.map(item =><p key={item}>{item}</p>)}
            {/* 传递对象 */}
            {props.userInfo.name}
            {/* 传递字符串 */}
            {props.messaeg}
            {/* 传递函数 点击按钮执行父组件传递的函数*/}
            <button onClick={props.getMessage}>触发父组件传入的函数</button>
            {/* 传递JSX */}
            {props.child}
        </div>

    )
}


//父组件
class App extends React.Component{
    //准备数据
    state = {
        list:[1,2,3],
        userInfo:{
            name:'hh',
            age:'30'
        },
        message:'this is message',
    }
    getMessage=()=>{
        console.log('父组件里的函数')
    }
    render(){
        return(
            <div>
                {/* 在子组件身上绑定属性 属性名可以自定义 保持语义化 */}
                <Son 
                    // 数组
                    list={this.state.list}
                    // 对象
                    userInfo = {this.state.userInfo} 
                    // 字符串
                    messaeg = {this.state.message}
                    // 函数
                    getMessage = {this.getMessage}
                    // JSX(传过去的是React的一个element对象)
                    child = {<span>this is span</span>}
                />
            </div>
        )
    }
}
export default App;

浏览器显示:
在这里插入图片描述
控制台显示:
在这里插入图片描述

props的解构赋值

对props进行解构赋值,会使写法更加简洁

写法一:

//函数式组件的Son
function Son(props){
 
    //对props解构赋值
    const {list,userInfo,message,getMessage,child} = props
        
	//对props进行解构赋值后,子组件接受数据时可以不用写props,用如下方式替代
	
         <div>
            传递数组
            {list.map(item =><p key={item}>{item}</p>)}
            {/* 传递对象 */}
            {userInfo.name}
            {/* 传递字符串 */}
            {message}
            {/* 传递函数 点击按钮执行父组件传递的函数*/}
            <button onClick={getMessage}>触发父组件传入的函数</button>
            {/* 传递JSX */}
            {child}
        </div>
        

    )
}

写法二:

//函数式组件的Son
 //对props解构赋值,直接在传参的时候解构
 //这里写的就是原生函数语法 props也是一个普通的js对象,所以原生支持的写法 这里都是可以的 放心大胆写
function Son({list,userInfo,message,getMessage,child}){
	//对props进行解构赋值后,子组件接受数据时可以不用写props,用如下方式替代
         <div>
            传递数组
            {list.map(item =><p key={item}>{item}</p>)}
            {/* 传递对象 */}
            {userInfo.name}
            {/* 传递字符串 */}
            {message}
            {/* 传递函数 点击按钮执行父组件传递的函数*/}
            <button onClick={getMessage}>触发父组件传入的函数</button>
            {/* 传递JSX */}
            {child}
        </div>        
    )
}

效果还和以前一样但是写法简洁了

子传父

子传父,实质上是子组件调用父组件传递过来的函数,将要传递给父组件的数字据作为函数的实参传入。

举例:

import React from 'react';

//App父组件 Son子组件
//父传子 props 函数

//子传父:子传父实质上是子组件调用父组件传递过来的函数,并且把想要传递的数据当成函数的实参传入即可
function Son(props){
    //对props进行解构赋值
    const {getSonMsg} = props;

    return (
        <div>this is Son<button onClick = {()=>{getSonMsg('这是来自于子组件的数据')}}>click</button></div>
    )
}

//父组件
class App extends React.Component{
    //准备数据
    state = {
        list : [1,2,3]
    }
    // 1.准备一个函数 传给子组件 SonMsg为要传的实参
    getSonMsg = (SonMsg)=>{
        console.log(SonMsg)
    }
    render () {
        return (
            <div>
                <Son getSonMsg = {this.getSonMsg}/>
            </div>
        )
    }
}  

export default App;

点击按钮,控制台打印出子组件传递给父组件的数据
在这里插入图片描述
上述子组件还可以这么写,代码如下:

function Son(props){
    //对props进行解构赋值
    const {getSonMsg} = props;
    
    function clickHander (){
        getSonMsg('这是来自子组件的数据')
    }

    return (
        <div>this is Son
            <button onClick = {clickHander}>click</button>
        </div>
    )
}

getSonMsg('这是来自于子组件的数据')单独拎出来写成一个独立的函数,然后再调用,可以保持模板的精简整洁。

兄弟组件传参

在这里插入图片描述
通过状态提升机制,利用共同的父组件实现兄弟通信。

举例:

import React from "react";

//App父组件 SonA SonB为子组件

// 目标:将B组件中的数据传给A
// 方案:
// 1.先把B中的数据通过子传父 传给App
// 2.再把App接收到的Son中的数据 通过父传子 传给A

function SonA(props) {
  const {sendAMsg} = props
  return (
    <div>
        this is A,{sendAMsg}
    </div>
  )
}
function SonB(props) {
  const { getBMsg } = props;
  const BMsg = "这里是来自于B组件的数据";
  return (
    <div>
      this is B<button onClick={() => getBMsg(BMsg)}>B给父发数据</button>
    </div>
  );
}
//父组件
class App extends React.Component {
    //声明一个传给A组件的数据
    state = {
        sendAMsg:'测试这里是否会变成父给A传来的数据'
    }
  //声明一个得到B组件数据的方法
  getBMsg = (msg) => {
    console.log(msg);
    //把msg数据交给sendAMsg
    this.setState({ 
        sendAMsg: msg
    })
  };
  render() {
    return (
      <div>
        <SonA sendAMsg ={this.state.sendAMsg}/>
        <SonB getBMsg={this.getBMsg} />
      </div>
    );
  }
}
export default App;

点击按钮前:
在这里插入图片描述
点击按钮后:
在这里插入图片描述

跨组件通信Context

即跨层传递,Context提供了一个无需为每层组件手动添加props,就能在组件树间进行数据传输的方法

在这里插入图片描述
实现步骤:

  1. 创建Context对象 导出 Provider 和 Consumer 对象
const {Provider,Consumer} = createContext()
  1. 使用Provider包裹根组件提供数据
<Provider value = {this.state.message}>
	{/*根组件*/}
</Provider>
  1. 需要用到数据的组件使用Consumber包裹获取数据
<Consumer>
	{value => /*基于 context 值进行渲染 */}
</Consumer>

举例:

import React, { createContext } from "react";

//App父组件 SonA SonB为子组件

//App -> A -> C
//App数据 -> C (跨过A传数据)

// 注意事项:1.上层组件和下层组件关系是相对的只要存在就可以使用 通常我们都会通过App作为数据提供方
// 2.这里涉及到的语法不是固定的,有两处,提供的位置 value提供数据 获取的位置{value=> 使用value做什么都可以}

//1.导入CreateContext()方法并执行,解构提供者和消费者
const { Provider, Consumer } = createContext();
function ComA() {
  return (
    <div>
      this is ComA
      <ComC />
    </div>
  );
}
function ComC() {
  return( 
    <div>
      this is ComC
      {/* 3. 通过Comsumer使用数据 */}
      <Consumer>
          {value=><span>{value}</span>}
      </Consumer>
    </div>
    )
}

//父组件
class App extends React.Component {
    // 准备数据
  state = {
    message: "this is message",
  };
  render() {
    return (
        // 2.使用provider包裹根标签
      <Provider value={this.state.message}>
        <div>
          <ComA />
        </div>
      </Provider>
    );
  }
}

export default App;

结果如图:

C组件后显示了this is message ,说明传递成功

在这里插入图片描述

练习

需求:
在这里插入图片描述

App组件提供数据,ListItem负责渲染数据,点击ListItem中的删除按钮,会删除相应的数据。

代码:

import React from "react";

//渲染列表
function ListItem({ item , delItem }) {
  return (
    <>
      <h3>{item.name}</h3>
      <p>{item.price}</p>
      <p>{item.info}</p>
      <button onClick={() => delItem(item.id)}>删除</button>
    </>
  );
}

//数据提供者 渲染ListItem组件 App-ListItem
//先不抽离组件 完成基础渲染后再去抽离
class App extends React.Component {
  state = {
    list: [
      { id: "1", name: "超级好吃的棒棒糖", price: 18.8, info: "开业大酬宾" },
      { id: "2", name: "超级好吃的大鸡腿", price: 34.2, info: "开业大酬宾" },
      { id: "3", name: "超级好吃的冰激凌", price: 14.2, info: "开业大酬宾" },
    ],
  }

  //给子组件传递的函数
  delItem = (id) => {
    this.setState({
        //filter函数 保留item.id !== id为true的item
        list: this.state.list.filter(item => item.id !== id)
    })
  }

  render() {
    return (
      <>
        {this.state.list.map((item) => (
          <ListItem item={item} key={item.id} delItem = {this.delItem}/>
        ))}
      </>
    );
  }
}

export default App;

结果:

点击删除会删除相对应的内容

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React组件通信可以通过props属性进行传递数据。子组件可以通过props接收父组件传递的数据,并进行相应的操作。在函数式组件中,可以直接通过props对象来获取父组件传递的数据。在类组件中,需要使用this.props来获取父组件传递的数据。\[1\] 另外,子组件也可以通过调用父组件传递过来的函数来实现子传父的通信。子组件可以将需要传递的数据作为函数的实参传入,并在子组件内部调用该函数。这样就可以将子组件的数据传递给父组件进行处理。\[3\] 总结起来,React组件通信可以通过props属性进行父传子和子传父的数据传递和操作。父组件通过props将数据传递给子组件,子组件通过props接收父组件传递的数据。子组件可以通过调用父组件传递的函数来将子组件的数据传递给父组件进行处理。\[1\]\[3\] #### 引用[.reference_title] - *1* *3* [React组件通信](https://blog.csdn.net/weixin_52148548/article/details/125287315)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [react组件通信](https://blog.csdn.net/weixin_39818813/article/details/125737028)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值