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.pswp.cn/news/909372.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909372.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909372.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【LangChain】4 基于文檔的問答

對于給定的文檔, 比如從PDF、網頁、公司主頁中提取構建的內部文檔集合&#xff0c;我們可以使用大語言模型來回答關于這些文檔內容的問題&#xff0c;以幫助用戶更有效地獲取和使用他們所需要的信息。這種方式非常有效且靈活地適用于實際應用場景&#xff0c;因為它不僅僅利用大…

基于Netty的TCP Server端和Client端解決正向隔離網閘數據透傳問題

背景 因為安裝了正向隔離網閘&#xff0c;導致數據傳輸的時候僅支持TCP協議和UDP協議&#xff0c;因此需要開發TCP Client和Server服務來將數據透傳&#xff0c;當前環境是獲取的數據并將數據轉發到kafka 1.引入依賴 <dependency><groupId>io.netty</groupId>…

Cursor鏈接遠程服務器實現項目部署

想獲取更多高質量的Java技術文章&#xff1f;歡迎訪問Java技術小館官網&#xff0c;持續更新優質內容&#xff0c;助力技術成長 技術小館官網 在軟件開發過程中&#xff0c;遠程服務器開發是一種常見的工作模式。通過遠程連接服務器進行代碼編寫和環境配置&#xff0c;可以充分…

Redis集群模式之Redis Cluster(3)

上篇文章我們講解了Redis Cluster的狀態監測與恢復過程&#xff0c;這篇文章我們來進行Redis Cluster內容的收尾&#xff0c;將其擴容和縮容的過程進行講解&#xff0c;并分析RedisCluster的優缺點。 擴容和縮容 當集群中出現容量限制或者其他一些原因需要擴容時&#xff0c;R…

Cursor ReAct Agent技術架構

一、架構核心思想 “零熵操作交給AI”理念 Cursor通過ReAct模式實現編程中重復性工作的自動化&#xff1a; 零熵操作&#xff1a;機械性任務&#xff08;代碼補全/格式化/重構/語法修復/導入管理&#xff09; Tab-away機制&#xff1a;一鍵接受AI建議&#xff0c;保持思維連續…

國學IP行業實戰洞察:聚焦創客匠人,解鎖創始人IP與知識變現新路徑

國學行業正經歷“文化價值”與“商業變現”的深度融合&#xff0c;2023年市場規模突破千億大關&#xff0c;年增速超 10%。在“IP化數字化”浪潮中&#xff0c;創客匠人作為垂直領域技術服務商&#xff0c;以全鏈路工具矩陣為支點&#xff0c;撬動國學創始人IP從內容生產到商業…

R語言開發入門完整指南

R語言開發入門完整指南 目錄 R語言簡介環境配置包管理基本語法數據類型和結構數據操作統計分析數據可視化編程結構實用技巧學習資源 R語言簡介 R是一種專為統計計算和圖形設計的編程語言&#xff0c;廣泛應用于數據分析、統計建模、機器學習和數據可視化。R語言具有以下特點…

ObservedV2裝飾器和Trace裝飾器

為了對嵌套類對象屬性變化直接觀測&#xff0c;華為提供了ObservedV2和Trace裝飾器。這兩個裝飾器必須搭配使用&#xff0c;單獨使用任何一個都不會起任何作用&#xff1b;在繼承類中也可監測&#xff1b;ObservedV2的類實例目前不支持使用JSON.stringify進行序列化&#xff0c…

6月計算機新書:深度學習、大模型、DeepSeek

六月&#xff0c;這個充滿活力與希望的季節&#xff0c;三本重磅新書《深度學習&#xff1a;基礎與概念》、《MCP極簡開發&#xff1a;輕松打造高效智能體》與《大模型應用開發&#xff1a;RAG實戰課》翩然而至&#xff0c;為我們開啟了一場探索科技前沿的奇妙之旅。一起來看詳…

扁平風格職場商務通用PPT模版分享

扁平風格PPT模版&#xff0c;創意卡通扁平化通用PPT模版&#xff0c;創意扁平化勵志論文答辯PPT模版&#xff0c;卡通職場商務PPT模版&#xff0c;職場培訓&#xff0c;項目策劃&#xff0c;工作總結類PPT模版&#xff0c;互聯網電子商務PPT模版 扁平風格職場商務通用PPT模版分…

jupyter內核崩潰

最近在做用k-mer評估基因組規模的任務&#xff0c;其中一個局部程序&#xff0c;想偷懶&#xff0c;直接在jupyter中跑了下結果&#xff0c;想看看這一小步處理如何&#xff0c;結果沒想到內核崩潰了&#xff01; 這一步我的草稿代碼如下&#xff1a; import pandas as pd imp…

Java企業技術趨勢分析:AI應用的落地實踐與未來展望

Java企業技術趨勢分析&#xff1a;AI應用的落地實踐與未來展望 開篇&#xff1a;技術趨勢與市場需求 在當前快速發展的數字化時代&#xff0c;人工智能&#xff08;AI&#xff09;已經成為推動企業創新和效率提升的關鍵力量。Java作為企業級應用開發的主流語言&#xff0c;正…

每日Prompt:Steve Winter風格插畫

提示詞 世界攝影大師杰作&#xff0c;極簡主義&#xff0c;Steve Winter風格&#xff0c;6只不同顏色的布偶貓圍成一圈&#xff0c;看向鏡頭中心&#xff0c;仰天視角&#xff0c;天空背景&#xff0c;高品質細節&#xff0c;超精細CG&#xff0c;高分辨率&#xff0c;最佳品質…

Vue3 + Element Plus 獲取表格列信息

在 Vue 3 和 Element Plus 中&#xff0c;可以通過以下步驟獲取表格的列信息&#xff1a; 實現步驟&#xff1a; 使用 ref 綁定表格實例 通過表格實例的 store.states.columns 獲取列數據 處理列信息&#xff08;過濾隱藏列、處理嵌套表頭等&#xff09; 示例代碼&#xf…

logger2js - JavaScript日志與調試工具庫

logger2js - JavaScript日志與調試工具庫 logger2js是一個功能強大的前端JavaScript日志與調試工具庫&#xff0c;提供了豐富的日志輸出、性能測試和代碼調試功能。該庫支持配置化引入&#xff0c;包含5種皮膚風格和豐富的API接口&#xff0c;如 a l e r t 增強方法、 alert增…

Stone 3D使用RemoteMesh組件極大的縮小工程文件尺寸

Stone 3D的工程文件tsp默認包含了場景中所有的對象和數據&#xff0c;這樣的好處是tsp可以單獨離線保存&#xff0c;但壞處是tsp文件通常偏大。 解決這個問題的方法是把外部glb模型文件通過RemoteMesh組件來加載。 首先創建一個空實體&#xff0c;然后給該空實體添加RemoteMe…

【深入剖析】攻克 Java 并發的基石:Java 內存模型 (JMM) 原理與實踐指南

0.引言 理解 JMM (Java Memory Model - JMM) 是掌握 Java 并發編程的關鍵&#xff0c;它定義了多線程環境下&#xff0c;線程如何與主內存以及彼此之間交互內存數據。 核心目標&#xff1a; JMM 旨在解決多線程編程中的三個核心問題&#xff1a; 原子性 (Atomicity)&#xf…

【Three.js】初識 Three.js

Threejs介紹 我們開發 webgl 主要是使用 threejs 這個庫&#xff0c;因為 webGL太難用&#xff0c;太復雜&#xff01;但是現代瀏覽器都支持WebGL&#xff0c;這樣我們就不必使用Flash、Java等插件就能在瀏覽器中創建三維圖形。 threejs 它提供-一個很簡單的關于WebGL特性的J…

【經驗總結】ECU休眠后連續發送NM報文3S后ECU網絡才被喚醒問題分析

目錄 前言 正文 1.問題描述 2.問題分析 3.驗證猜想 4.總結 前言 ECU的上下電/休眠喚醒在ECU開發設計過程中最容易出問題且都為嚴重問題,最近在項目開發過程中遇到ECU休眠狀態下連續發送NM報文3S后才能喚醒CAN網絡的問題,解決問題比較順利,但分析過程中涉及到的網絡休…

企業架構框架深入解析:TOGAF、Zachman Framework、FEAF與Gartner EA Framework

執行摘要 企業架構&#xff08;EA&#xff09;是一項至關重要的實踐&#xff0c;它使組織能夠協調其業務戰略、運營流程和技術基礎設施&#xff0c;以實現整體戰略目標。企業架構框架作為結構化的方法論和綜合性工具&#xff0c;旨在管理企業級系統的固有復雜性&#xff0c;提…