React 跨组件通信 -- 学习笔记

1,464 阅读1分钟

使用Context来解决跨组件通信

React.createContext

  • React.createContext()
    • Consumer
    • Provider

注意项

  1. Provider 组件上的属性,要传递的内容都写成它的属性
<Provider value={{
        counter: this.state.counter,
        incrementCounter: this.incrementCounter,
        decrementCounter: this.decrementCounter
    }}>
        { this.props.children } 
</Provider>
  1. Consumer 组件包裹的里面是一个函数,用 return 返回要显示的内容
    • 参数就是 Provider 属性名和值得对象结构
 <CounterConsumer>
    {
        (arg) => {
        	// arg 是一个对象 里面装的是Provide组件的属性名和值的对象结构
            // {counter: 100, incrementCounter: ƒ, decrementCounter: ƒ}
            return (
                <span>{arg.counter}</span>
            )
        }
    }
 </CounterConsumer>
  1. React.createContext() 我们结构的时候通常会给Consumer起一个别名

个人理解

  • 这样做解决了什么问题:Provide,Consumer用来解决夸多层组件传值问题,如果我在Counter 组件里面加其他组件也是可以直接通过 arg 来访问 Provider 上传过来的值得

  • 方便记忆:这个有点像vue 中的 provide/inject ,父组件provide数据,后代组件里面要用到时就用 inject 注入接收

    • 最外层套一个 Provider 组件,
    • App 组件上没有加属性,跨过这个组件传递数据到下一级
    • 子组件 用 Consumer 包裹接收

demo

import React, { Component, Fragment, createContext } from 'react'
import { render } from 'react-dom'

const {
    Provider,
    Consumer: CounterConsumer
} = createContext()

class CounterProvide extends Component {
    constructor() {
        super()
        this.state = {
            counter: 100
        }
    }
    incrementCounter = () => {
        this.setState({
            counter: this.state.counter + 1
        })
    }
    decrementCounter = () => {
        this.setState({
            counter: this.state.counter - 1
        })
    }
    render() {
        return (
            <Provider value={{
                counter: this.state.counter,
                incrementCounter: this.incrementCounter,
                decrementCounter: this.decrementCounter
            }}>
                {
                // 老是忘记写这句
                // CounterProvide 组件子组件都显示在这个里面
                this.props.children
                } 
                
            </Provider>
        )
    }
}

class CountBtn extends Component {
    render() {
        return (
            <CounterConsumer>
                {arg => {
                    return (
                        <button onClick={
                            this.props.type === "increment" ? arg.incrementCounter : arg.decrementCounter
                        }>
                            {this.props.children}
                        </button>
                    )
                }}
            </CounterConsumer>
        )
    }
}

class Counter extends Component {
    render() {
        return (
            <CounterConsumer>
                {
                    (arg) => {
                        return (
                            <span>{arg.counter}</span>
                        )
                    }
                }
            </CounterConsumer>
        )
    }
}

class App extends Component {
    render() {
        return (
            <Fragment>
                <CountBtn type="increment">+</CountBtn>
                <Counter></Counter>
                <CountBtn type="decrement">-</CountBtn>
            </Fragment>
        )
    }
}
render(
    <CounterProvide>
        <App />
    </CounterProvide>,
    document.querySelector('#root')
)