React组件的通讯方式

392 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

不管是Vue或者是React,组件通讯都是必备的,本文主要介绍React组件之间通讯方式。

1.父子之间的通讯

1.1 父传子

父组件通过props传参给子组件

    // 父组件
    import { useState } from 'react';
    import Child from './child'

    export default function HelloWorld() {
      const [name, setName] = useState('豆豆')
      return (
        <div>
          // 把name传递给子组件
          <Child name={name} />
        </div>
      )
    }
    // 子组件
    import { useState } from 'react';
    // 子组件利用对象解构赋值接收父组件传递的 name
    export default function Child({name}) {

      return (
        <div>
          // 子组件展示父组件传递的 name 值
          { name }
        </div>
      )
    }

1.2 子传父

父组件传递 changeName 方法给子组件,让子组件执行该方法,通过函数传参的方式来完成子组件给父组件参传

    // 父组件
    import { useState } from 'react';
    import Child from './child'

    export default function HelloWorld() {
      const [name, setName] = useState('豆豆')
      // val的值通过子组件传递过来
      const changeName = val => {
        setName(val)
      }
      return (
        <div>
          {name}
          // 把 changeName 传递给子组件
          <Child changeName={changeName} />
        </div>
      )
    }
    // 子组件
    import { useState } from 'react';
    // 子组件接收 changeName 方法
    export default function Child({changeName}) {
        
      const handleClick = () => {
        // 执行父组件传递过来的方式,并且给父组件传值
        changeName('一只豆豆')
      }
      return (
        <div>
          <button onClick={handleClick}>click my</button>
        </div>
      )
    }

2.跨组件的通讯

2.1 先创建一个 MyContext.js

利用React.createContext创建一个MyContext,并且可以设置默认值

    import React from 'react'
    export const MyContext = React.createContext(
      // 在这里可以设置默认值
      { name: '豆豆' },
    )

2.2 在祖先组件引入 MyContext.js

MyContext.Provider包裹父组件 通过 value={xxx} 传值

    import { useState, } from 'react';
    import Child from './child'
    import { MyContext } from './context'

    export default function HelloWorld() {
      const [name, setName] = useState('一只豆豆')

      return (
        <div>
           // 包裹组件并且传递 name
          <MyContext.Provider value={name}>
            <Child />
          </MyContext.Provider>

        </div>
      )
    }

2.3 子组件引入孙子组件

只需要引入son组件 使用即可,不需要任何操作了

    import { useState } from 'react';
    import Son from './son'
    export default function Child() {
      return (
        <div>
          <Son />
        </div>
      )
    }

2.4 孙子组件使用传递过来的数据

MyContext.Consumer包裹一个函数式组件,该函数式组件的参数,可以接收该组件的上级组件中最近一个被MyContext.Provider包裹的组件中传递给MyContext.Provider的属性value的数据。

    import { useState } from 'react';
    import { MyContext } from './context'
    export default function Son() {
      return (
        <div>
          <MyContext.Consumer>
            { value => (<div>{ value }</div>) }
          </MyContext.Consumer>
        </div>
      )
    }

3.EventBus通讯

Vue2有EventBus的API,通过 $on$emit 来进行通讯, React没有 EventBusAPI,我们可以利用node.js提供的events.js来实现
npm install events --save 先下载 events.js

3.1 先创建一个 bus.js 文件

    import { EventEmitter } from 'events'
    const eventBus = new EventEmitter()
    export default eventBus

3.2 兄弟组件Aemit发送事件

    import bus from './bus'
    export default function A() {
        const handleClick = () => {
            bus.emit('click', '爱在西元前')
        }
        return (
            <>
                <button onClick={handleClick}>click my</button>
            </>
        )
    }

3.3 兄弟组件Bon监听事件

    import { useEffect } from 'react';
    import bus from './bus'
    export default function B() {
        bus.on('click', val => {
            console.log('val', val); // 爱在西元前
        })
        return (
            <>
                <div>
                    兄弟组件B
                </div>
            </>
        )
    }

3.4 兄弟组件Boff销毁事件

    import { useEffect } from 'react';
    import bus from './bus'
    export default function B() {
        
        const handleClick = val => {
            console.log('val', val); // 爱在西元前
        }
        useEffect(() => {
            // 监听事件
            bus.on('click', handleClick)
            return () => {
                // 销毁事件
                bus.off('click', handleClick)
            }
        }, [])

        return (
            <>
                <div>
                    test
                </div>
            </>
        )
    }

4.父组件调用子组件方法

在Vue中可以通过ref去调用子组件的方式;
在React中可以通过useImperativeHandle把子组件的方法暴露出去;

    // 父组件
    import React, { useRef } from "react"
    import Child from './child'
    export default function Father() {
        const myRef = useRef()
        const handleClick = () => {
            // 点击按钮时执行子组件的handleClick方法
            myRef.current.handleClick()
        }
        return (
            <>
                <div>
                    父组件
                    <button onClick={handleClick}>click my</button>
                    <Child ref={myRef} />
                </div>
            </>
        )
    }
    // 子组件
    import React, { useImperativeHandle, forwardRef } from "react"
    const Child = (props, ref) => {
        useImperativeHandle(ref, () => ({
            handleClick: () => {
                console.log('七里香');
            }
        }))
        return (
            <>
                <div>
                    子组件
                </div>
            </>
        )
    }

    export default forwardRef(Child) // useImperativeHandle配合forwardRef一起使用

结语

有帮助的话,给个赞哈。如果有错误欢迎在评论区指出。