【前端知识】React 基础巩固(三十七)——自定义connect高阶组件

news2024/9/27 15:18:00

React 基础巩固(三十七)——自定义connect高阶组件

一、手撸一个自定义connect高阶组件

import { PureComponent } from "react";
import store from "../store";

/**
 * connect的参数:
 * 参数一: 函数
 * 参数二: 函数
 * 返回值: 函数
 */
export default function connect(mapStateToProps, mapDispatchToProps) {
  // 返回一个高阶组件,本质也是函数
  return function (WrapperComponent) {
    class NewComponent extends PureComponent {
      constructor(props) {
        super(props);
        // 将接收到的mapStateToProps赋给state,用于部分值修改时的浅层比较、更新state
        this.state = mapStateToProps(store.getState());
      }
      componentDidMount() {
        this.unsubscribe = store.subscribe(() => {
          this.setState(mapStateToProps(store.getState()));
        });
      }

      componentWillUnmount() {
        this.unsubscribe();
      }

      render() {
        // 将接收到的mapStateToProps、mapDispatchToProps传入要返回的新组件中
        const stateObj = mapStateToProps(store.getState());
        const dispatchObj = mapDispatchToProps(store.dispatch);
        return (
          <WrapperComponent {...this.props} {...stateObj} {...dispatchObj} />
        );
      }
    }
    return NewComponent;
  };
}

二、目前的问题

import store from "../store";

从这行代码可以看到,目前的connect直接引用了上级目录的store,过于依赖目前既定的store,这样不利于复用。假设另一个项目的store所在位置不在上级目录中,则会出现问题。

三、优化上面的丐版connect

为了让所有人都能使用,我们应该把这种“写死”的做法换成让开发者自己传入一个store:

  1. 构建一个StoreContext,用于创建Store的上下文(src/hoc/StoreContext.js):

    import { createContext } from "react";
    
    export const StoreContext = createContext()
    
  2. 当我们在项目的index.js中引入connect时,引入并使用该上下文,让开发者手动传入当前的store(src/index.js):

    import React from "react";
    import ReactDOM from "react-dom/client";
    import { Provider } from "react-redux";
    import { StoreContext } from "./hoc";
    import App from "./App";
    import store from "./store";
    
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(
      // <React.StrictMode>
    
      <Provider store={store}>
        <StoreContext.Provider value={store}>
          <App />
        </StoreContext.Provider>
      </Provider>
      // </React.StrictMode>
    );
    
    
  3. 在connect中,通过 contextType 共享从 Provider 中传入的 store 变量,将原来直接引用的 store 替换成 this.context(hoc/connect.js):

    import { PureComponent } from "react";
    import { StoreContext } from "./StoreContext";
    
    /**
     * connect的参数:
     * 参数一: 函数
     * 参数二: 函数
     * 返回值: 函数
     */
    export function connect(mapStateToProps, mapDispatchToProps) {
      // 返回一个高阶组件,本质也是函数
      return function (WrapperComponent) {
        class NewComponent extends PureComponent {
          constructor(props, context) {
            super(props);
            // 将接收到的mapStateToProps赋给state,用于部分值修改时的浅层比较、更新state
            this.state = mapStateToProps(context.getState());
          }
          componentDidMount() {
            this.unsubscribe = this.context.subscribe(() => {
              this.setState(mapStateToProps(this.context.getState()));
            });
          }
    
          componentWillUnmount() {
            this.unsubscribe();
          }
    
          render() {
            // 将接收到的mapStateToProps、mapDispatchToProps传入要返回的新组件中
            const stateObj = mapStateToProps(this.context.getState());
            const dispatchObj = mapDispatchToProps(this.context.dispatch);
            return (
              <WrapperComponent {...this.props} {...stateObj} {...dispatchObj} />
            );
          }
        }
    
        // 在类组件中,通过 contextType 共享store变量
        NewComponent.contextType = StoreContext
    
        return NewComponent;
      };
    }
    
    
  4. 最后,在hoc中构建index.js,将优化后的connect导出(hoc/index.js):

    export { StoreContext } from "./StoreContext";
    export { connect } from "./connect";
    
    
  5. 在界面中使用现在优化后的connect:

    import React, { PureComponent } from "react";
    import { connect } from "../hoc";
    import { addNumber } from "../store/features/counter";
    
    export class About extends PureComponent {
      render() {
        const { counter } = this.props;
        return (
          <div>
            <h2>About Counter: {counter}</h2>
          </div>
        );
      }
    }
    
    const mapStateToProps = (state) => ({
      counter: state.counter.counter,
    });
    
    const mapDispatchToProps = (dispatch) => ({
      addNumber(num) {
        dispatch(addNumber(num));
      },
    });
    
    export default connect(mapStateToProps, mapDispatchToProps)(About);
    
    
  6. 查看效果,与之前效果一致:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/809243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TiProxy 尝鲜

说明 最近发现 tidb 有个 GitHub - pingcap/TiProxy 仓库&#xff0c;抱着好奇的心态想试试这个组件的使用效果。于是按照文档的介绍在本地环境使用tiup做了一些实验&#xff0c;现在将实验过程和实验结果分享给大家。 TiProxy介绍 官方README介绍的已经很清楚了&#xff0c;…

QT 调用USB免驱摄像头

文章目录 前言一、界面布局二、QImageEncoderSettings类三、图像的显示总结 前言 本篇文章来讲解一下如何使用QT调用摄像头&#xff0c;这里我使用的是USB免驱动摄像头&#xff0c;使用不需要按照驱动QT就可以调用到摄像头。 一、界面布局 这里使用QT设计师进行界面的布局&a…

数据结构:树的存储结构

学习树之前&#xff0c;我们已经了解了二叉树的顺序存储和链式存储&#xff0c;哪么我们如何来存储普通型的树结构的数据&#xff1f;如下图1&#xff1a; 如图1所示&#xff0c;这是一颗普通的树&#xff0c;我们要如何来存储呢&#xff1f;通常&#xff0c;存储这种树结构的数…

vmware磁盘组使用率100%处理

今天在外办事时&#xff0c;有客户发过来一个截图&#xff0c;问vmware 磁盘组空间使用率100%咋办&#xff1f;如下图&#xff1a; 直接回复&#xff1a; 1、首先删除iso文件等 2、若不存在ISO文件等&#xff0c;找个最不重要的虚拟机直接删除&#xff0c;删除后稍等就会释放…

数据分析-关于指标和指标体系

一、电商指标体系 二、指标体系的作用 三、统计学中基本的分析手段

记一次解决FTPS上传的文件为空的问题

最近公司的vsftpd文件服务由之前的FTP传输改成了FTPS的&#xff0c;虽然代码做了相应的调整&#xff0c;但是始终有个问题&#xff0c;就是在服务器上文件创建成功了&#xff0c;名称也是正确的&#xff0c;可是一看大小确是0&#xff0c;于是查看日志 用项目上传的始终是失败&…

mybatis-config.xml-配置文件详解

文章目录 mybatis-config.xml-配置文件详解说明文档地址:配置文件属性解析properties 属性应用实例 settings 全局参数定义应用实例 typeAliases 别名处理器举例说明 typeHandlers 类型处理器environments 环境environment 属性应用实例 mappers配置 mybatis-config.xml-配置文…

vue除了子组件抛出的额外参数,父组件如何传递额外参数

以下为一个简单的demo,只为记录一下 很多时候如果我们多个地方使用同一函数时,往往就需要进行判断了,但是组件库返回的函数携带的参数没办法让我们做多余的判断 这时就需要传递多余的参数了 方法一 使用箭头函数 <template><div><el-switchv-model"value&…

2023年中秋节国庆节是几月几号开始休假国庆中秋双节放假几天?

2023年中秋节国庆节是几月几号开始休假国庆中秋双节放假几天&#xff1f; 2023年中秋节与国庆节双节相遇一起放假长大8天; 2023年中秋节与国庆节放假时间是从2023年9月29日开始至10月6日共计8天&#xff0c;10月7日、10月8日补班&#xff1b; 2023年中秋节怎么购买月饼省钱又…

Jenkins配置自动化构建的几个问题

在创建构建任务时&#xff0c;填写git远程仓库地址时&#xff0c;出现以下报错 解决此报错先排查一下linux机器上的git版本 git --version 如果git 版本过低&#xff0c;可能会导致拉取失败&#xff0c;此时需要下载更高的git版本。 参考 Git安装 第二个解决办法报错信息中…

Ansible的脚本 --- playbook 剧本

文章目录 一、playbook剧本的组成创建剧本运行playbook二、定义、引用变量三、指定远程主机sudo切换用户四、when条件判断五、迭代Templates 模块tags 模块 一、playbook剧本的组成 playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0…

SpringCloudAlibaba之整合openFeign

一.openFeign的入门使用&#xff08;4步&#xff09; 1.引入openFeign的依赖包&#xff0c;记得父项目中要加上SpringCloud依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactI…

VSCode新手快速下载、安装、使用

目录 下载 安装 1、许可协议 2、安装位置 3、开始菜单文件夹 4、附加任务 5、确认安装 6、完成 使用 1、汉化&#xff08;设置中文界面&#xff09; 2、设置 下载 进入VSCode官方页面&#xff0c;选择自己系统对应的下载链接VSCode默认提供的User Installer版本。但…

【解决】el-tree报Cannot read property ‘getCheckedKeys‘ of undefined

如果你报错 Cannot read property getCheckedKeys of undefined 或者 Cannot read property getCheckedNodes of undefined 只要在你的在<el-tree>上加个这个&#xff0c;就可以了 ref"tree"

某圆形变电站三维建模模型-glb格式-三维漫游-三维可视化-三维模拟巡检

资源介绍 某个圆形变电站的三维建模模型&#xff0c;glb格式&#xff0c;适用于three.js开发测试&#xff0c;可用来做一些三维室内漫游测试、室内导航测试和三维模拟巡检测试 资源下载地址

联想拯救者笔记本切换独显直连游戏体验翻倍、火力全开“嗨”起来

最早的游戏本是由独显负责图形运算&#xff0c;然后直接向屏幕输出所有画面的。但独显负责所有工作&#xff0c;无时无刻都在耗电&#xff1b;撇开游戏模式下高负载的功耗不谈&#xff0c;即便在省电模式下功耗也比核显高得多。 英伟达发布的Optimus混合输出技术&#xff0c;在…

马哈鱼 v.sqlflow.cn 上线试用

马哈鱼数据血缘工具从2023年8月开始开通国内云版本的服务&#xff0c;相比国外版本&#xff0c;访问速度有很大的提升&#xff0c;访问域名为https://v.sqlflow.cn 2023年8月和9月注册的用户可免费获得价值 3000 元的一年高级帐户&#xff0c;可以使用马哈鱼数据血缘工具全部付…

Caffeine本地缓存技术

说明&#xff1a;Caffeine是本地缓存方案&#xff0c;在所有本地缓存中命中率最佳&#xff0c;参考下图&#xff08;引自http://t.csdn.cn/oiQlH&#xff09;&#xff0c;本文介绍Caffeine在SpringBoot项目中的应用。 使用 例如现在有两个接口&#xff0c;一个查询所有用户&am…

Spring 6【数据校验Validation、JSR 303 和 Hibernate 实现】(十三)-全面详解(学习总结---从入门到深化)

目录 数据校验Validation 2.JSR 303 和 Hibernate 实现 数据校验Validation 1.数据校验介绍 数据校验分为客户端数据校验和服务端数据校验。都是为了保证数据完整性的。 客户端数据校验直接使用客户端脚本校验即可。例如在B/S模型项目中&#xff0c;可以选择使用JavaScript…

Flowable中间事件-中间信号捕获事件

定义 信号中间事件分为 Catching 事件和 Throwing 事件&#xff0c;即信号中间捕获事件&#xff08;Signal Intermediate Catch Event&#xff09;和信号中间抛出事件&#xff08;Signal Intermediate Throwing Event&#xff09;。 当流程执行到信号中间捕获事件时就会中断在…