简单聊下 React 中祖孙级组件之间的通信方式

介绍

本文主要通过两种方式实现,一是通过 components,一是通过 hooks,通过 cdn 方式引入,阅读大概需要 7-8 min。

hooks 实现需要 react 版本在 16.8 以上

准备

  1. react.development.js 文件 - 用于操作 React 相关 api
  2. react-dom.development.js 文件 - 用于把 React 组件渲染成 DOM
  3. babel.min.js 文件 - 用于把 jsx 语法转化为 js

具体实现如下:如果没有可方便去 react_extends 项目 grandson_communication 分支 上查看,项目代码都附属到上面了

<script src="../js/17.0.1/react.development.js"></script>
<script src="../js/17.0.1/react-dom.development.js"></script>
<script src="../js/17.0.1/babel.min.js"></script>

<script type="text/babel">
// some js
</script>

方式一:components 实现

基本准备如下:

点击查看代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Components</title>
  </head>
  <body>
    <div id="root"></div>

    <script src="../js/17.0.1/react.development.js"></script>
    <script src="../js/17.0.1/react-dom.development.js"></script>
    <script src="../js/17.0.1/babel.min.js"></script>

    <script type="text/babel">
      class Father extends React.Component {
        render() {
          return (
            <div>
              father <ChildA />
            </div>
          )
        }
      }

      class ChildA extends React.Component {
        render() {
          return (
            <div>
              ChildA <ChildB />
            </div>
          )
        }
      }

      class ChildB extends React.Component {
        render() {
          return (
            <div>
              ChildB <ChildC />
            </div>
          )
        }
      }

      class ChildC extends React.Component {
        render() {
          return <div>ChildC</div>
        }
      }

      ReactDOM.render(<Father />, document.getElementById('root'))
    </script>
  </body>
</html>

这里实现了几个组件的逐级嵌套,依次是 Father > ChildA > ChildB > ChildC,下面说下祖孙级传参的具体实现的几个核心点

  1. 引入 React.createContext 变量
  2. 解构出 Provider、Consumer
  3. Provider 包裹子组件,并通过 value 属性传入需要传递的参数

这里的 Provider 和 Consumer 都是 Context 下的组件,想要具体了解的小伙伴可 翻阅官网 Context,推荐直接看下面代码,简洁明了。
如果使用了 Provider,那么 value 属性一定要传

具体实现:

点击查看代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Components</title>
  </head>
  <body>
    <div id="root"></div>

    <script src="../js/17.0.1/react.development.js"></script>
    <script src="../js/17.0.1/react-dom.development.js"></script>
    <script src="../js/17.0.1/babel.min.js"></script>

    <script type="text/babel">
      const myComponentContent = React.createContext() // 引入 context 变量
      const { Provider, Consumer } = myComponentContent // 解构出对应的组件

      class Father extends React.Component {
        render() {
          return (
            <div>
              father
              <Provider value={{ id: 1, name: 'zxn', text: '我是一段文本' }}>
                <ChildA />
              </Provider>
            </div>
          )
        }
      }

      class ChildA extends React.Component {
        static contextType = myComponentContent
        render() {
          const { id, name, text } = this.context
          return (
            <div>
              ChildA
              <div>
                我是从 Father 组件引入的变量,分别是 id: {id}、name: {name}
                、text:{text}
              </div>
              <ChildB />
            </div>
          )
        }
      }

      class ChildB extends React.Component {
        static contextType = myComponentContent
        render() {
          const { id } = this.context
          return (
            <div>
              ChildB
              <div>我是从 Father 组件引入的变量,我只用了 id: {id}</div>
              <ChildC />
            </div>
          )
        }
      }

      class ChildC extends React.Component {
        render() {
          return (
            <div>
              ChildC
              <Consumer>
                {(value) => {
                  return (
                    <div>
                      我是从 Father 组件引入的变量,我采用了回调形式,我只用了
                      name: {value.name}
                    </div>
                  )
                }}
              </Consumer>
            </div>
          )
        }
      }

      ReactDOM.render(<Father />, document.getElementById('root'))
    </script>
  </body>
</html>

方式二:hooks 实现

简单说下 hooks 存在的意义,它解决了哪些问题:

  1. 简化了 class 形式创建组件的代码量
  2. 允许函数式组件使用 class 组件的状态和生命周期
  3. 可拆分为更细粒度的函数,更方便复用

简单说下它如何使用:

  1. 把上面的 class 组件全部改为 函数组件
  2. 引入 Context 变量的流程不变
  3. 变的只有在具体的子组件引用时的写法,去除了必须声明 static 静态方法的步骤

具体实现:

点击查看代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Hooks</title>
  </head>
  <body>
    <div id="root"></div>

    <script src="../js/17.0.1/react.development.js"></script>
    <script src="../js/17.0.1/react-dom.development.js"></script>
    <script src="../js/17.0.1/babel.min.js"></script>

    <script type="text/babel">
      const myComponentContent = React.createContext() // 引入 context 变量
      const { Provider, Consumer } = myComponentContent // 结构出对应的组件

      function Father() {
        return (
          <div>
            father
            <Provider value={{ id: 1, name: 'zxn', text: '我是一段文本' }}>
              <ChildA />
            </Provider>
          </div>
        )
      }

      function ChildA() {
        const { id, name, text } = React.useContext(myComponentContent)
        return (
          <div>
            ChildA
            <div>
              我是从 Father 组件引入的变量,分别是 id: {id}、name: {name}
              、text:{text}
            </div>
            <ChildB />
          </div>
        )
      }

      function ChildB() {
        const { id } = React.useContext(myComponentContent)
        return (
          <div>
            ChildB
            <div>我是从 Father 组件引入的变量,我只用了 id: {id}</div>
            <ChildC />
          </div>
        )
      }

      function ChildC() {
        return (
          <div>
            ChildC
            <Consumer>
              {(value) => {
                return (
                  <div>
                    我是从 Father 组件引入的变量,我采用了回调形式,我只用了
                    name: {value.name}
                  </div>
                )
              }}
            </Consumer>
          </div>
        )
      }

      ReactDOM.render(<Father />, document.getElementById('root'))
    </script>
  </body>
</html>

这里要注意下,使用函数式组件的时候,render 就不需要了,直接 return 就好

最后

稍微加了点粉色,最终实现效果皆为如下:
最终效果图

posted @ 2021-12-17 13:34  土地情缘  阅读(307)  评论(0编辑  收藏  举报