手写redux的connect方法, 使用了subscribe获取最新数据
一. 公共方法文件
1. connect文件
import React, { useState } from "react";
import MyContext from "./MyContext";
import _ from "lodash";// 模拟react-redux的 connect高阶函数
const connect = (mapStateToProps, mapDispatchToProps) => {return (Component) => props => wrapper(Component, {mapStateToProps, mapDispatchToProps, ...props});
};const wrapper = (Comp, props) => {const {mapStateToProps, mapDispatchToProps, ...rest} = propsreturn <MyContext.Consumer>{store => {const dispatch = _.get(store, 'dispatch');const dispatchs = mapDispatchToProps(dispatch);// store.subscribe监听store.getState()获取最新的值const [states, setStates] = useState({})store.subscribe(() => {const state1 = store.getState();setStates(mapStateToProps(state1))});return <Comp {...{...states, ...dispatchs, ...rest}}/>;}}</MyContext.Consumer>}export default connect;
2. MyContext文件:
import React from "react";
import createContext from './createContext'const MyContext = createContext({});export default MyContext
3. createContext文件:
import React from "react";const createContext = ({}) => {let value = {};const Provider = (props) => {value = props.value;return <>{props.children}</>;};const Consumer = ({ children }: { children: any }) => {return <>{typeof children === "function" ? children(value) : children}</>;};return { Provider, Consumer };
};export default createContext;
4. reducer文件
// 新增列表数据和改变数组数据
// 将业务逻辑拆分到一个单独文件中,方便进行状态管理
import _ from 'lodash';export interface StateProps {id: number;text: string;isFinished: boolean;}export interface ActionProps {type: string;[key: string]: any;}interface IStateObjectProps {pickerArr: StateProps[];filterTag: 'SHOW_ALL'|'SHOW_FINISHED'|'SHOW_NOT_FINISH';dispatch: any;}
const reducer = (state: IStateObjectProps, action: ActionProps) => {console.log(state, action, 'reducer');const pickerArr0 = _.get(state, 'pickerArr')||[];switch (action.type) {case "ADD":return {...state,pickerArr: [...pickerArr0, _.get(action, 'todo')]};case "CHANGESTATUS":const pickerArr = _.map(pickerArr0, (item) => {if (item.id === action.id) {return Object.assign({}, item, { isFinished: !_.get(item, 'isFinished') });}return item;})||[];return {...state,pickerArr,}case 'SET_VISIBILITY_FILTER': const filterTag = action.filterTag;return {...state,filterTag,};default:return state || {};}};export default reducer
5. mapStateToProps文件:
import React from "react";
import _ from "lodash";
import store from "./store";// 不同类型的 todo 列表const getVisibleTodos = (todos, filter) => {switch (filter) {case "SHOW_ALL": // 全部显示return todos;case "SHOW_FINISHED":return todos.filter((t) => t.isFinished);case "SHOW_NOT_FINISH":return todos.filter((t) => !t.isFinished);default:return todos;}
};export const mapStateTotProps = (state) => {// console.log(state, 'mapStateTotProps', store)return {todoList: getVisibleTodos(_.get(state, 'pickerArr')||[], _.get(state, 'filterTag'))|| [],}
}
6. mapDispatchToProps文件
import React from "react";
import _ from "lodash";
import { StateProps } from "./reducer";export const mapDispatchToProps = (dispatch) => {// console.log(dispatch, 'mapDispatchToProps============')// 筛选todo列表const onFilterTodoList = (filterTag) => {dispatch({ type: 'SET_VISIBILITY_FILTER', filterTag, });};const changeTodo = (id: number) => {dispatch({ type: "CHANGESTATUS", id: id });};// 添加todoconst addTodo = (todo: StateProps) => {dispatch({ type: "ADD", todo });};const showAll = () => onFilterTodoList("SHOW_ALL");const showFinished = () => onFilterTodoList("SHOW_FINISHED");const showNotFinish = () => onFilterTodoList("SHOW_NOT_FINISH");return {changeTodo,addTodo,showAll,showFinished,showNotFinish,};
}
由mapStateToProps文件和mapDispatchToProps文件可知, 我们需要想办法获取最新的state, 和通用的dispatch方法, 也就是以下所说的store文件里面的默认导出对象:
7. store文件:
import React from 'react';
import reducer from './reducer'function createStore(reducer) {let state = null;const listeners = [];const subscribe = (fn) => listeners.push(fn);const getState = () => state;const dispatch = (action) => {const state1 = reducer(state, action);state = state1// 因为是在获取到最新的state的值之后有执行的监听回调, 所以使用store.subscribe可以监听到最新的state的值!!!listeners.forEach((fn) => fn());return state}// dispatch({}) return { getState, dispatch, subscribe, reducer }
}const store = createStore(reducer)console.log(store.getState(), 'oldState======')
store.subscribe(() => {const newState = store.getState() // 数据可能变化,需要监听最新的console.log(newState, 'newState====');
})export default store;
8. ContextProvider组件:
import React from "react";
import MyContext from "./MyContext";
import store from "./store";
import _ from "lodash";// 父组件
const ContextProvider = ({ children }) => {return <MyContext.Provider value={store}>{children}</MyContext.Provider>;
};export default ContextProvider;
二. 使用公共文件
1. TodoInput组件
import React, { useState } from "react";
import "./TodoInput.scss";
import connect from './connect';
import { mapStateTotProps } from "./mapStateToProps";
import { mapDispatchToProps } from "./mapDispatchToProps";// 子组件
const TodoInput = (props) => {const [text, setText] = useState("");const {addTodo,showAll,showFinished,showNotFinish,} = props;const handleChangeText = (e: React.ChangeEvent) => {setText((e.target as HTMLInputElement).value);};const handleAddTodo = () => {if (!text) return;addTodo({id: new Date().getTime(),text: text,isFinished: false,});setText("");};return (<div className="todo-input"><inputtype="text"placeholder="请输入代办事项"onChange={handleChangeText}value={text}/><button onClick={handleAddTodo}>+添加</button><button onClick={showAll}>show all</button><button onClick={showFinished}>show finished</button><button onClick={showNotFinish}>show not finish</button></div>);
};export default connect(mapStateTotProps, mapDispatchToProps)(TodoInput);
2. TodoList组件
import React from "react";
import TodoItem from "./TodoItem";
import _ from "lodash";
import connect from "./connect";
import { mapStateTotProps } from "./mapStateToProps";
import { mapDispatchToProps } from "./mapDispatchToProps";const TodoList = (props) => {const { todoList } = props;return (<><p>checckbox-list: </p><div className="todo-list">{_.map(todoList, (item) => (<TodoItem key={_.get(item, "id")} todo={item || {}} />))}</div><hr /></>);
};export default connect(mapStateTotProps, mapDispatchToProps)(TodoList);
3. TodoItem组件
import _ from 'lodash';
import React from "react";
import connect from './connect';
import { mapStateTotProps } from "./mapStateToProps";
import { mapDispatchToProps } from "./mapDispatchToProps";// 孙子组件
const TodoItem = (props: any) => {const { todo, changeTodo } = props;// 改变事项状态const handleChange = () => {changeTodo(_.get(todo, 'id'));}return (<div className="todo-item"><input type="checkbox" checked={todo.isFinished} onChange={handleChange} /><span style={{ textDecoration: _.get(todo, 'isFinished') ? 'line-through' : 'none' }}>{todo.text}</span></div>)
}export default connect(mapStateTotProps, mapDispatchToProps)(TodoItem);
4. Todo组件:
import React from "react";
import TodoInput from "./TodoInput";
import TodoList from "./TodoList";// 父组件
const Todo = () => {return (<><TodoInput /><TodoList /></>);
};
export default Todo;
5. App组件使用ContextProvider包裹Todo组件
import React from "react";
import Todo from './mockConnectProvider/Todo'
import ContextProvider from './mockConnectProvider/ContextProvider'const App: React.FC = () => {return (<ContextProvider><Todo /></ContextProvider>);
};export default App;
效果图如下:
相关文章:

手写redux的connect方法, 使用了subscribe获取最新数据
一. 公共方法文件 1. connect文件 import React, { useState } from "react"; import MyContext from "./MyContext"; import _ from "lodash";// 模拟react-redux的 connect高阶函数 const connect (mapStateToProps, mapDispatchToProps) &…...

数据结构--B树
目录 回顾二叉查找树 如何保证查找效率 B树的定义 提炼 B树的插入和删除 概括B树的插入方法如下 B树的删除 导致删除时,结点不满足关键字的个数范围时(需要借) 如果兄弟不够借,需要合体 回顾B树的删除 B树 B树的查找 …...

【音视频|ALSA】基于alsa-lib开发ALSA应用层程序--附带源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...

嵌入式养成计划-43----QT QMainWindow中常用类的使用--ui界面文件--资源文件的添加--信号与槽
一百零九、QMainWindow中常用类的使用 109.1 菜单栏 QMenuBar 菜单栏 QMenuBar 最多只能有一个 109.2 工具栏 QToolBar 工具栏 QToolBar 可以有多个 109.3 状态栏QStatusBar 状态栏 QStatusBar 最多只能有一个 109.4 浮动窗口QDockWidget 浮动窗口 可以有多个 109.5 代…...
【Yarn】清除Yarn的缓存,更新Yarn本身、更新项目的依赖项
要清除Yarn的缓存,可以运行以下命令: yarn cache clean这将清除Yarn的缓存目录。 要更新Yarn本身,可以运行以下命令: yarn self-update这将下载并安装最新版本的Yarn。 如果要更新项目的依赖项,可以运行以下命令&a…...
点云从入门到精通技术详解100篇-雨雾环境下多传感器融合SLAM方法(续)
目录 4 基于球面投影的激光视觉融合里程计 4.1 引言 4.2 视觉惯性里程计 4.2.1特征点提取与匹配...
解决GET请求入参@NotNull验证不生效问题
一、问题 get请求NotNull验证不生效 二、解决方案 两个步骤: 在该方法的controller类上加Validated;在参数面前加NotNull; 三、其他注解 //被注释的元素必须为null Null //被注释的元素不能为null NotNull //被注释的元素必须为true Ass…...

《golang设计模式》第三部分·行为型模式-01-责任链模式(Chain of Responsibility)
文章目录 1 概念1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1 概念 责任链(Chain of Responsibility)是指将客户端请求处理的不同职责对象组成请求处理链。 客户端只需要将请求交付到该链上,而不需要关心链上含有哪些对象。请求…...

环境变量【使用命令行参数引出环境变量】
前提:命令行参数 大家在写C/C程序的时候肯定见过下面这种情况: main函数里面携带的参数,平常写代码过程中很少用到这两个参数,接下来我们就研究一下 我们也不知道 指针数组argv里面到底保存的是什么,也不知道这个a…...

【Java 进阶篇】JavaScript BOM History 详解
当用户浏览网页时,可以使用JavaScript的BOM (Browser Object Model)中的History对象来访问浏览器的历史记录。这个对象允许您在不更改页面的情况下导航到不同的历史记录项,或者查看有关用户访问过的页面的信息。 在本篇博客中,我们将围绕Jav…...

【计算机网络】https协议
文章目录 1 :peach:基本概念:peach:1.1 :apple:什么是HTTPS?:apple:1.2 :apple:什么是加密?:apple:1.3 :apple:常见的加密方式:apple:1.3.1 :lemon:对称加密:lemon:1.3.2 :lemon:⾮对称加密:lemon: 1.4 :lemon:数据指纹:lemon: 2 :peach:HTTPS的⼯作过程…...

React之受控组件和非受控组件以及高阶组件
一、受控组件 受控组件,简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据 举个简单的例子: class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai }…...

中国移动集采120万部,助推国产5G赶超iPhone15
近期媒体纷纷传出消息指中国移动将大规模集采,预计将采购国产5G手机120万台,加上另外两家运营商的集采数量,估计集采数量可能达到300万部,如此将有助于它在国内高端手机市场赶超苹果。 国产5G手机在8月底突然上市,获益…...

华为云HECS服务器下docker可视化(portainer)
一、docker安装 华为云HECS安装docker-CSDN博客 二、portainer安装 portainer地址:Portainer: Docker and Kubernetes Management Platform 当前portainer分CE(开源版) 和 BE(商业版),用CE即可 1 创建…...

postman发送soap报文示例
一、soap简介 soap是一种基于XML的协议 二、postman发送soap请求 1、发送post请求,url: https://www.dataaccess.com/webservicesserver/NumberConversion.wso 2、headers设置,添加Content-Type,值为text/xml 添加SOAP…...

力扣-python-两数之和
题解: class Solution(object):def twoSum(self, nums, target):# 遍历列表for i in range(len(nums)):# 计算需要找到的下一个目标数字res target-nums[i]# 遍历剩下的元素,查找是否存在该数字if res in nums[i1:]:# 若存在,返回答案。这里…...

算水质TDS加温度补偿
先上图,就图里这款水质检测,用树莓派3/4的话,要配个温度检测作为温度校正,以及一个adc 元器件。我选ds18b20和ads1115。 再把模拟数据计算过程放一下: 温度检测元器件在农历钟那里提过,就是同款。此处先测个…...

wps/word 如何让表格的标题和表格名称文本(表1-1 xxx)跨页显示(已解决)
第一步: 打开wps 创建一个跨页的表格表格,如下图 第二步 大家都知道 表格标题跨页 就是1)在菜单表格工具 点击重复标题 或者 2)表格属性--》行--》在各页顶端以标题行形式出现,详细如下图。 1) 第一…...

攻防世界web篇-PHP2
直接点击进入到http网页中,会得到这样一个界面 这里,我最开始使用了burp什么包也没有抓到,然后接着又用nikto进行探测,得到的只有两个目录,当时两个目录打开后,一个是fond界面,一个是这个网页的…...
Kotlin中的步长
步长是 Kotlin 中用于迭代区间或集合时控制迭代步进的概念。在 Kotlin 中,我们可以使用 step 关键字来指定迭代时的步长。 在 Kotlin 中,有多种方式可以定义一个区间(Range)。我们将通过以下示例代码来展示不同类型的区间以及如何…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...