React 父子、跨层级 组件通信了解及使用

1,781 阅读3分钟

组件通信

1.父子通信[具备相同父亲的兄弟组件]: props属性基于ref

2.祖先和后代 具备相同祖先的平行组件

父子组件通信

父子组件传值本质上还是传递属性的问题

props【父传子】

传值:

{/* 子组件 xxx为变量*/}
<Child xxx={xxx}/>

// 子组件接收参数
function Child(props){
    let {xxx} = props
    return (<div>{xxx}</div>)
}

回调函数【子传父】【单向数据流,需要借助回调函数去修改父组件的值】

子组件修改组件的值


{/* 子组件  这里的xxx为回调函数*/}
<Child xxx={xxx}/>

// 子组件接收参数
function Child(props){
    let {xxx} = props
    return (
        // onClick 也可以为其他
        <button onClick={xxx}>按钮</button>
    )
}

写一个简单完整例子: 实现点击按钮,数据加1的简单操作

图片.png

Demo为父组件,DemoMain、DemoChange 为子元素

Demo.jsx

import React, { useState } from 'react'
import DemoMain from './DemoMain';
import DemoChange from './DemoChange';

export default function Demo() {
    const [count, setCount] = useState(0);
    const change = () => {
        setCount(count + 1);
    }
    return (
        <div>
            <div>总计:{count}</div>
            <DemoMain count={count} />
            <DemoChange change={change} />
        </div>
    )
}

DemoMain.jsx

import React from 'react'

export default function DemoMain(props) {
    let { count } = props
    return (
        <div style={{ margin: '20px 0' }}>
            展示内容:{count}
        </div>
    )
}

DemoChange.jsx

import React from 'react'
import { Button } from 'antd'

export default function DemoChange(props) {
    let { change } = props
    return (
        <div>
            <Button type="primary" onClick={change.bind(null)}>按钮</Button>
        </div>
    )
}

上面的例子主要为演示作用,实际开发以业务为准 Demo传值给DemoMain DemoMain使用props接收传递过来的参数 DemoChange 触发Demo内的change回调函数,来达到修改兄弟组件内的数据

这个等于也是兄弟组件之间使用值,依托于父组件,从而获取到值,达到兄弟组件之间交互的目的

运行结果:

图片.png

祖先/后代(或平行)组件间通信

当组件之间的嵌套结构较深,如果基于属性一级一级传值会很麻烦!

上下文 React.createContext() 【代码较多】

上下文存入信息:

ThemeContext.Provider

基于上下文对象中,提供的Provider组件,用来:

  • 向上下文中存储信息:value 属性指定的值就是要存储的信息
  • 当祖先组件更新,render 重新执行,会把最新的狀态值,再次存储到上下文对象中!!
<ThemeContext.Provider value={{
            count,
            change
        }}>
            <div>
                <div>总计:{count}</div>
                <DemoMain />
                <DemoChange />
            </div>
        </ThemeContext.Provider>

获取上下文传值方式

类组件

获取上下文

方案一: contextType

  • 导入创建的上下文对象
  • 给类组件设置静态私有属性 contextType = 上下文对象
  • 从 this.context 获取需要的信息即可
import React, { Component } from 'react'
import ThemeContext from './ThemeContext';
import { Button } from 'antd'

export default class DemoChange extends Component {
    // 类组件 获取上下文方式 第一种: contextType
    static contextType = ThemeContext;
    render() {
        let { change } = this.context
        return (
            <div>
                <Button type="primary" onClick={change}>按钮</Button>
            </div >
        )
    }
}

第二种:Consumer 适用于函数组件及类组件

<ThemeContext.Consumer>
    {
        context => {
            return 渲染的视图
        }
    }
</ThemeContext.Consumer>

上下文传值 例子:

下面存入及获取的方案都在例子里面写了: Demo 存入上下文信息,类组件和函数组件存入的方式一致,都是 ThemeContext.Provider DemoMain是函数组件 DemoChange是类组件

目录结构:

图片.png

目录结构和上个例子一致,多了个ThemeContext.js

ThemeContext.js

import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;

Demo.jsx

import React, { useState } from 'react'
import ThemeContext from './ThemeContext';
import DemoMain from './DemoMain';
import DemoChange from './DemoChange';

export default function Demo() {
    const [count, setCount] = useState(0);
    const change = () => {
        setCount(count + 1);
    }
    return (
        <ThemeContext.Provider value={{
            count,
            change
        }}>
            <div>
                <div>总计:{count}</div>
                <DemoMain />
                <DemoChange />
            </div>
        </ThemeContext.Provider>
    )
}

DemoMain.jsx

import React, { useContext } from 'react'
import ThemeContext from './ThemeContext';

export default function DemoMain() {
    //  ****  函数组件 获取上下文方式 第一种: useContext
    let { count } = useContext(ThemeContext)
    return (
        <div style={{ margin: '20px 0' }}>
            展示内容:{count}
        </div>
    )

    // ****   函数组件 获取上下文方式 第二种: Consumer
    // return (
    //     <ThemeContext.Consumer>
    //         {context => {
    //             let { count } = context
    //             return (
    //                 <div style={{ margin: '20px 0' }}>
    //                     展示内容:{count}
    //                 </div>
    //             )
    //         }}
    //     </ThemeContext.Consumer>
    // )
}

DemoChange.jsx

import React, { Component } from 'react'
import ThemeContext from './ThemeContext';
import { Button } from 'antd'

export default class DemoChange extends Component {
    // 类组件 获取上下文方式 第一种: contextType
    static contextType = ThemeContext;
    render() {
        let { change } = this.context
        return (
            <div>
                <Button type="primary" onClick={change}>按钮</Button>
            </div >
        )
    }

    // *******  类组件 获取上下文方式 第二种: Consumer
    // render() {
    //     return (
    //         <ThemeContext.Consumer>
    //             {
    //                 context => {
    //                     let { change } = context
    //                     return (
    //                         <div>
    //                             <Button type="primary" onClick={change}>按钮</Button>
    //                         </div >
    //                     )
    //                 }
    //             }
    //         </ThemeContext.Consumer>
    //     )
    // }

}

状态管理库

redux / react-redux