当前位置: 首页 > java >正文

Redux 原理深度剖析

1. Redux 实现

定义 Action 和 Reducer 类型,为了简便,先用JavaScript来演示。

1.1. 定义Action和Reducer类型

// 定义 Action 类型
/*** @typedef {Object} Action* @property {string} type*/// 定义 Reducer 类型
/*** @callback Reducer* @param {any} state* @param {Action} action* @returns {any}*/

Action 对象包含一个 type 属性,用于描述要执行的操作。

Reducer 是一个函数,接收当前状态和 Action,并返回新的状态。

1.2. 创建Store

// 创建 store
/*** @type {CreateStore}*/
function createStore(reducer, initialState, enhancer) {if (enhancer) {return enhancer(createStore)(reducer, initialState);}let state = initialState;let listeners = [];function getState() {return state;}function dispatch(action) {state = reducer(state, action);listeners.forEach(listener => listener());}function subscribe(listener) {listeners.push(listener);return () => {listeners = listeners.filter(l => l !== listener);};}return { getState, dispatch, subscribe };
}

createStore 函数用于创建 Redux store。

getState 方法返回当前状态。

dispatch 方法接收一个 Action,并使用 reducer 计算新状态。

subscribe 方法用于订阅状态变化。

1.3. 合并多个 Reducer

// 合并多个 reducer
/*** @param {Object<string, Reducer>} reducers* @returns {Reducer}*/
function combineReducers(reducers) {return (state = {}, action) => {const newState = {};for (const key in reducers) {newState[key] = reducers[key](state[key], action);}return newState;};
}

combineReducers 函数将多个 reducer 合并成一个,以便管理复杂的状态结构。

1.4. 组合函数

// 组合函数
/*** @param {...function} funcs* @returns {function}*/
function compose(...funcs) {if (funcs.length === 0) {return arg => arg;}if (funcs.length === 1) {return funcs[0];}return funcs.reduce((a, b) => (...args) => a(b(...args)));
}

compose 函数用于组合多个函数,从右到左依次执行。

1.5. 应用中间件

// 应用中间件
/*** @param {...Middleware} middlewares* @returns {function(CreateStore): CreateStore}*/
function applyMiddleware(...middlewares) {return createStore => (reducer, initialState) => {const store = createStore(reducer, initialState);let dispatch = store.dispatch;const middlewareAPI = {getState: store.getState,dispatch: action => dispatch(action),};const chain = middlewares.map(middleware => middleware(middlewareAPI));dispatch = compose(...chain)(store.dispatch);return {...store,dispatch,};};
}

applyMiddleware 函数用于应用中间件,增强 dispatch 方法。

1.6. Redux整体源码实现

// 定义 Action 类型
/*** @typedef {Object} Action* @property {string} type*/// 定义 Reducer 类型
/*** @callback Reducer* @param {any} state* @param {Action} action* @returns {any}*/// 定义 Store 类型
/*** @typedef {Object} Store* @property {function(): any} getState* @property {function(Action): void} dispatch* @property {function(function(): void): function(): void} subscribe*/// 创建 store
/*** @type {CreateStore}*/
function createStore(reducer, initialState, enhancer) {if (enhancer) {return enhancer(createStore)(reducer, initialState);}let state = initialState;let listeners = [];function getState() {return state;}function dispatch(action) {state = reducer(state, action);listeners.forEach(listener => listener());}function subscribe(listener) {listeners.push(listener);return () => {listeners = listeners.filter(l => l !== listener);};}return { getState, dispatch, subscribe };
}// 合并多个 reducer
/*** @param {Object<string, Reducer>} reducers* @returns {Reducer}*/
function combineReducers(reducers) {return (state = {}, action) => {const newState = {};for (const key in reducers) {newState[key] = reducers[key](state[key], action);}return newState;};
}// 组合函数
/*** @param {...function} funcs* @returns {function}*/
function compose(...funcs) {if (funcs.length === 0) {return arg => arg;}if (funcs.length === 1) {return funcs[0];}return funcs.reduce((a, b) => (...args) => a(b(...args)));
}// 应用中间件
/*** @param {...Middleware} middlewares* @returns {function(CreateStore): CreateStore}*/
function applyMiddleware(...middlewares) {return createStore => (reducer, initialState) => {const store = createStore(reducer, initialState);let dispatch = store.dispatch;const middlewareAPI = {getState: store.getState,dispatch: action => dispatch(action),};const chain = middlewares.map(middleware => middleware(middlewareAPI));dispatch = compose(...chain)(store.dispatch);return {...store,dispatch,};};
}// 示例代码
const initialState = { count: 0 };const counterReducer = (state = initialState, action) => {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };case 'DECREMENT':return { count: state.count - 1 };default:return state;}
};const loggerMiddleware = ({ getState }) => next => action => {console.log('will dispatch', action);next(action);console.log('state after dispatch', getState());
};const store = createStore(counterReducer,initialState,applyMiddleware(loggerMiddleware)
);store.subscribe(() => {console.log('state updated:', store.getState());
});store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });

2. 示例代码

2.1. 定义 Reducer 和初始状态

const initialState = { count: 0 };const counterReducer = (state = initialState, action) => {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };case 'DECREMENT':return { count: state.count - 1 };default:return state;}
};

counterReducer 是一个简单的 reducer,处理 INCREMENT 和 DECREMENT 两种 action。

2.2. 定义中间件

const loggerMiddleware = ({ getState }) => next => action => {console.log('will dispatch', action);next(action);console.log('state after dispatch', getState());
};

loggerMiddleware 是一个日志中间件,用于在 action 分发前后打印日志。

2.3. 创建 Store 并应用中间件

const store = createStore(counterReducer,initialState,applyMiddleware(loggerMiddleware)
);store.subscribe(() => {console.log('State updated:', store.getState());
});store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });

创建 store 并应用 loggerMiddleware 中间件。

订阅状态变化并分发两个 action。

3. 将 Redux 与 React 结合

3.1. 创建自定义 Hook

import React from 'react';
import { useSyncExternalStore } from 'react';/*** 自定义 Hook,使用 useSyncExternalStore 订阅 Redux store 的状态变化* @param {Store} store* @returns {any} 当前状态*/
function useReduxStore(store) {return useSyncExternalStore(store.subscribe, // 订阅状态变化store.getState, // 获取当前状态store.getState // SSR 期间获取当前状态 (此处简化处理));
}

useReduxStore 是一个自定义 Hook,利用 useSyncExternalStore 订阅 Redux store 的状态变化。

3.2. 编写示例组件

function Counter() {const state = useReduxStore(store); // 使用自定义 Hook 获取 Redux 状态return (<div><p>Count: {state.count}</p><button onClick={() => store.dispatch({ type: 'INCREMENT' })}>Increment</button><button onClick={() => store.dispatch({ type: 'DECREMENT' })}>Decrement</button></div>);
}

Counter 组件使用 useReduxStore Hook 获取当前状态,并通过 Redux store 分发动作。

3.3. 渲染组件

import { createRoot } from 'react-dom/client';const container = document.getElementById('root');
const root = createRoot(container);
root.render(<Counter />);
// 将 Counter 组件渲染到页面

使用 createRoot 渲染 Counter 组件到页面上的 DOM 节点中。

4. Mantine 的状态 ts 实现

import { useSyncExternalStore } from 'react';export type MantineStoreSubscriber<Value> = (value: Value) => void;
type SetStateCallbackValue = (value: Value) => Value;export interface MantineStore<Value> {getState: () => Value;setState: (value: Value | SetStateCallbackValue) => void;updateState: (value: Value | SetStateCallbackValue) => void;initialize: (value: Value) => void;subscribe: (callback: MantineStoreSubscriber<Value>) => () => void;
}export type MantineStoreValue<Store extends MantineStore<any>> = ReturnType<Store['getState']>;export function createStore<Value extends Record<string, any>>(initialState: Value
): MantineStore<Value> {let state = initialState;let initialized = false;const listeners = new Set<MantineStoreSubscriber<Value>>();return {getState() {return state;},updateState(value) {state = typeof value === 'function' ? value(state) : value;},setState(value) {this.updateState(value);listeners.forEach((listener) => listener(state));},initialize(value) {if (!initialized) {state = value;initialized = true;}},subscribe(callback) {listeners.add(callback);return () => listeners.delete(callback);},};
}export function useStore<Store extends MantineStore<any>>(store: Store) {return useSyncExternalStore<MantineStoreValue<Store>>(store.subscribe,() => store.getState(),() => store.getState());
}

5. Redux 的其他概念

异步的支持,因为 reducer 的设计,导致处理过程是依照纯函数和同步函数处理的,所以我们需要额外考虑异步的事情,使用 redux-thunk、redux-sage的方案。

http://www.xdnf.cn/news/14179.html

相关文章:

  • 备忘录模式:文本编辑器撤销功能实现
  • 2025年渗透测试面试题总结-字节跳动[实习]安全研究员(题目+回答)
  • 浏览器 报502 网关错误,解决方法2
  • 论文精读Lami-Detr:Open-Vocabulary Detection with Language Model Instruction
  • 芯片的起点——从硅到晶圆制造
  • 用Python写一个可视化大屏
  • 简说ping、telnet、netcat
  • 论文阅读-单目视觉惯性系统时间标定
  • MySQL 锁学习笔记
  • 计算机网络-自顶向下—第二章应用层-重点复习笔记
  • 在C++中的封装(Encapsulation)
  • Linux学习笔记:PCIe内核篇(1):初始化与枚举流程
  • 第1章 C# 和 .NET 框架 笔记
  • MCP简介和应用
  • 第十七章 Linux之大数据定制篇——Shell编程
  • ES知识合集(四):高级篇
  • 20250614让NanoPi NEO core开发板在Ubuntu core16.04系统下使用耳机播音测试
  • 「Linux文件及目录管理」目录结构及显示类命令
  • Python虚拟环境的使用
  • SpringBoot源码解析(十一):条件注解@ConditionalOnClass的匹配逻辑
  • 如何调优Kafka
  • LeetCode 第71题 简化路径(繁琐)
  • thinkphp8提升之查询
  • Nature Machine Intelligence 北京通研院朱松纯团队开发视触觉传感仿人灵巧手,实现类人自适应抓取
  • 开心灿烂go开发面试题
  • 如何自动化测试 DependencyMatcher 规则效果(CI/CD 集成最佳实践)
  • 免费OCPP协议测试工具
  • FreeRTOS定时器
  • C++/OpenCV地砖识别系统结合 Libevent 实现网络化 AI 接入
  • 如何写出优秀的单元测试?