• React中的context的用法和使用场景和发布-订阅模式


    使用场景

    如果你在组件间传递的数据逻辑比较复杂,可以使用redux;

    如果组件层级不多,可以使用props;

    如果层级较深,数据逻辑简单,可以使用context或者发布-订阅模式。

     在 React 16.3 之前,Context API 由于存在种种局限性,并不被 React 官方提倡使用,开发者更多的是把它作为一个概念来探讨。而从 v 16.3.0 开始,React 对 Context API 进行了改进,新的 Context API 具备更强的可用性。

    以下是代码演示:

    1.创建一个Context,const ThemeContext = React.createContext('light')

    2.在父组件中用ThemeContext.Provider包裹子组件,用value传递数据

    3.如果子组件是函数组件,要使用context时,需要用ThemeContext.Consumer包裹,通过value拿到数据;如果子组件是类组件,要使用context时,需要指定 contextType 读取当前的 theme context,这有两种方式,一种是在类组件中声明静态属性static contextType = ThemeContext,另一种是在组件外定义ThemedButton.contextType = ThemeContext,通过this.context拿到数据

    import React from 'react'
    
    // 创建 Context 填入默认值(任何一个 js 变量)
    const ThemeContext = React.createContext('light')
    let { Consumer, Provider } = ThemeContext;
    
    // 底层组件 - 函数是组件
    function ThemeLink(props) {
        // const theme = this.context // 会报错。函数式组件没有实例,即没有 this
    
        // 函数式组件可以使用 Consumer
        return <Consumer>
            {value => <p>link's theme is {value}</p>}
        </Consumer>
    }
    
    // 底层组件 - class 组件
    class ThemedButton extends React.Component {
        // 指定 contextType 读取当前的 theme context。
        // static contextType = ThemeContext // 也可以用 ThemedButton.contextType = ThemeContext
        render() {
            const theme = this.context // React 会往上找到最近的 theme Provider,然后使用它的值。
            return <div>
                <p>button's theme is {theme}</p>
            </div>
        }
    }
    ThemedButton.contextType = ThemeContext // 指定 contextType 读取当前的 theme context。
    
    // 中间的组件再也不必指明往下传递 theme 了。
    function Toolbar(props) {
        return (
            <div>
                <ThemedButton />
                <ThemeLink />
            </div>
        )
    }
    
    class App extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                theme: 'light'
            }
        }
        render() {
            // 用Provider包起来
            return <Provider value={this.state.theme}>
                <Toolbar />
                <hr />
                <button onClick={this.changeTheme}>change theme</button>
            </Provider>
        }
        changeTheme = () => {
            this.setState({
                theme: this.state.theme === 'light' ? 'dark' : 'light'
            })
        }
    }
    
    export default App

    发布-订阅模式

    class myEventEmitter {
      constructor() {
        // eventMap 用来存储事件和监听函数之间的关系
        this.eventMap = {};
      }
      // type 这里就代表事件的名称
      on(type, handler) {
        // hanlder 必须是一个函数,如果不是直接报错
        if (!(handler instanceof Function)) {
          throw new Error("哥 你错了 请传一个函数");
        }
        // 判断 type 事件对应的队列是否存在
        if (!this.eventMap[type]) {
          // 若不存在,新建该队列
          this.eventMap[type] = [];
        }
        // 若存在,直接往队列里推入 handler
        this.eventMap[type].push(handler);
      }
      // 别忘了我们前面说过触发时是可以携带数据的,params 就是数据的载体
      emit(type, params) {
        // 假设该事件是有订阅的(对应的事件队列存在)
        if (this.eventMap[type]) {
          // 将事件队列里的 handler 依次执行出队
          this.eventMap[type].forEach((handler, index) => {
            // 注意别忘了读取 params
            handler(params);
          });
        }
      }
      off(type, handler) {
        if (this.eventMap[type]) {
            // >>> 无符号位移 自然数(大于等于0的整数)>>>0 还是该自然数
            // -1 >>> 0 =4294967295 对数组没有影响
            // 关于位移相关内容,查看二进制和位移知识篇
          this.eventMap[type].splice(this.eventMap[type].indexOf(handler) >>> 0, 1);
        }
      }
    }

    待续。。。

  • 相关阅读:
    让c像python一样可以在命令行写代码并且编译
    动态链接库找不到 : error while loading shared libraries: libgsl.so.0: cannot open shared object file: No such file or directory
    为什么shell中变量赋值不能有空格
    在hyper安装openwrt
    linux扩展lvm磁盘
    docker的基本使用
    tmux与vim主题不一致
    linux centos cli all proxy
    couchDB入门
    tmux复制到windows剪贴板/粘贴板的坑
  • 原文地址:https://www.cnblogs.com/kewenxin/p/12988700.html
Copyright © 2020-2023  润新知