React组件间通信

不借助redux等状态管理工具的React组件间的通信解决方法

组件通信分类

React组件间通信分为2大类,3种情况:

  • 1)有嵌套关系的
    • 父->子
    • 子->父
      这里的父通指上级组件,不一定是直属上级,可跨级
  • 2)无嵌套关系的
    • 兄弟组件间
    • 无共同上级组件的

父->子(props)

  • 方法一:父组件向子组件传递 props,子组件得到 props 后进行相应的处理。(跨多层组件的时候只需要一层一层传下去就行)


    image.png
// 父组件 Parent.js:
import React,{ PureComponent } from "react";
import Children from "./Children.js";

export default class Parent extends PureComponent{
  state = {
    title: '父组件',
  }
  outputDesc = () => {
    console.log('父组件向子组件通信,通过props传递参数或者函数');
  }
  render(){
    const { title } = this.state;
    const childProps = {
      title,
      onOutputDesc: this.outputDesc,
    }
    return(
      <Children {...childProps} />
    )
  }
}
// 子组件 Children.js:
// 界面上会显示出 【这是子组件获取到的父组件的title:父组件】
// 点击控制台会打印出 【父组件向子组件通信,通过props传递参数或者函数】
export default class Children extends PureComponent{
  render(){
    const { title, outputDesc } = this.props;
    return(
      <Fragment>
        <p>这是子组件获取到的父组件的title:{title}</p>
        <button onClick={onOutputDesc}>点击</button>
      </Fragment>
    )
  }
}

  • 方法二:通过context

使用 React提供的context API(Provider 和 Consumer)
对于方法一,如果要通信的组件间的层次结构很深,中间的每一层组件都要去传递 props,增加了复杂性,并且这些 props 并不是这些中间组件自己所需要的。
当组件层次在三层以上时建议使用context,context做的事情就是创建一个上下文对象,并且对外暴露提供者(通常在组件树中上层的位置)和消费者,在上下文之内的所有子组件,
都可以访问这个上下文环境之内的数据,并且不用通过props。可以理解为有一个集中管理state的对象,并限定了这个对象可访问的范围,在范围之内的子组件都能获取到它内部的值。

// context.js
// Provider和Consumer总是成对出现
import React from 'react'
const demoContext = React.createContext();
const demoProvider = demoContext.Provider;
const demoConsumer = demoContext.Consumer;
export demoProvider;
export demoConsumer;

// 父组件
import React from 'react'
import List from './List'
import { demoProvider } from './context'

export default class Todo extends React.PureComponent {
  state = {
      list: [],
  }
  task = React.createRef()
  handleClick = () => {
      const list = [...this.state.list, this.task.current.value];
      this.setState({ list });
      this.task.current.value = '';
  }
  deleteTask = (index) => {
    const { list } = this.state;
    list.splice(index, 1);
    this.setState({ list });
  }
  render() {
    return (
      // 在父(祖先)级组件中把要传递内容放到value里面
      <demoProvider value={{deleteTask: this.deleteTask}}>
          <input type="text" ref={this.task}/>
          <button onClick={this.handleClick}> 添加 </button>
          <List list={this.state.list} deleteTask={this.deleteTask}/>
      </demoProvider>
    );
  }
}
// 子组件
import React from 'react'
import {demoConsumer} from './context'
export default class List extends React.PureComponent{

  render() {
    const { list } = this.props
    return (
      <demoConsumer>
        // 后代组件中的组件放在Consumer里面, 内部是一个函数, 这个函数接受一个对象作为参数, 参数是Provider里面提供的值
        {
          ({ deleteTask }) => {
            return list.map((item, index) => {
              return (
                <li key={item}>
                  { item }
                  <button onClick={()=>{deleteTask(index)}}> 删除 </button>
                </li>
              )
            })
          }
        }
      </demoConsumer>
    );
  }
}

子->父(回调)

父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,向父组件通信。

// 父组件 Parent.js:
import React,{ PureComponent, Fragment } from "react";
import Children from "./Children.js";

export default class Parent extends PureComponent{
  state = {
    description: '',
  }
  handleChangeDesc = (props) => {
    this.setState({description: '子组件向父组件通信,通过回调传递参数: 在子组件中点击按钮改变父组件state中的属性})
  }
  render(){
    const { description } = this.state;
    const childProps = {
      onChangeDesc: this.handleChangeDesc,
    }
    return(
      <Fragment>
        <p>{description}</p>
        <Children {...childProps} />
      </Fragment>
    )
  }
}

// 子组件 Children.js:
// 界面上会显示出更新后的description值 【子组件向父组件通信,通过回调传递参数: 在子组件中点击按钮改变父组件state中的属性】
export default class Children extends PureComponent{
  changeParentDesc = () => {
    const { onChangeDesc } = this.props;
    onChangeDesc({description: '子组件向父组件通信,通过回调传递参数: 在子组件中点击按钮改变父组件state中的属性'});
  }
  render(){
    const { title, outputDesc } = this.props;
    return(
      <button onClick={this.changeParentDesc}>点击</button>
    )
  }
}

兄弟组件间

方法一:利用共同的上级组件作为中间人进行通信(子1->父->子2)

方法二:通过自定义发布-订阅模式的事件实现(以Node.js中events模块的EventEmitter 类为例,这个会在我的另一篇文章中细讲)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 组件间不同的嵌套关系,会导致不同的通信方式。常见的有:父组件向子组件通信、子组件向父组件通信、没有嵌套关系的组件之...
    南风知我意ZD阅读 1,357评论 0 0
  • 1. 组件间通信1.1.父组件向子组件通信1.2.子组件向父组件通信1.3.跨级组件间通信1.4.无嵌套关系组件间...
    爱吃芋圆的小w阅读 468评论 0 2
  • React作为前端的新一代主流框架,因其组件化的思想,彻底革新了前端停留在DOM操作的古老开发方式。使用React...
    徐丶清风阅读 555评论 0 3
  • 最近学习浅尝则止的学习了一下react.js这个UI的框架,react这个库给我的最大的感觉就是它能够完全的接管U...
    璀璨天宇阅读 608评论 0 0
  • 这次用的彩铅,画了一个小时。 先用铅笔打稿,打完后可以用橡皮擦淡,然后用黑笔描边,我觉得这样方便上色。
    沉默岛主阅读 810评论 2 20

友情链接更多精彩内容