react中多個頁面,數(shù)據(jù)相互依賴reducer問題及解決
場景
典型的電商商品管理頁面復(fù)雜狀態(tài)場景,涉及多個模塊數(shù)據(jù)聯(lián)動、動態(tài)生成 SKU、屬性和額外參數(shù)注入等。關(guān)鍵點(diǎn)是 避免組件之間直接相互監(jiān)聽,保持邏輯集中化
頁面模塊
- 基本信息
- 商品名稱
- 分類 / 平臺分類
- 詳細(xì)信息(富文本/描述)
- 規(guī)格名稱、規(guī)格值
- SKU 列表:基于規(guī)格動態(tài)生成
- SKU 可能包含額外字段(如價格、庫存、額外參數(shù))
- 動態(tài)數(shù)據(jù)依賴
切換平臺分類 → 獲取動態(tài)屬性、額外參數(shù) → 注入到 SKU
修改規(guī)格名稱 → 重新生成 SKU
核心問題:
- SKU 生成依賴規(guī)格數(shù)據(jù)、額外參數(shù)
- 額外參數(shù)依賴平臺分類
- 數(shù)據(jù)變化涉及多個模塊聯(lián)動,容易出現(xiàn)重復(fù)計算或死循環(huán)
useReducer(或者 useImmerReducer) 比直接在組件里用一堆 useState + useEffect 更適合,原因如下:
- 集中管理狀態(tài):所有頁面狀態(tài)都在一個地方管理,組件只負(fù)責(zé)渲染和觸發(fā)操作。
- 統(tǒng)一處理聯(lián)動邏輯:SKU 生成、額外參數(shù)注入、動態(tài)屬性拉取都在 reducer 內(nèi)完成,不會散落在各組件的 useEffect 里。
- 避免死循環(huán):不需要組件間相互監(jiān)聽狀態(tài)變化,更新邏輯集中在 reducer 內(nèi)部。
- 便于維護(hù)和擴(kuò)展:新增字段或聯(lián)動規(guī)則,只需改 reducer,不用改每個組件
狀態(tài)設(shè)計
import { useReducer } from 'react';
import produce from 'immer';
interface ProductState {
basicInfo: {
name: string;
categoryId: number;
platformCategoryId: number;
description: string;
};
specs: {
name: string;
values: string[];
}[];
dynamicAttributes: Record<string, any>; // 平臺分類動態(tài)屬性
extraParams: Record<string, any>; // 平臺分類額外參數(shù)
skuList: SKU[];
}
interface SKU {
id?: string;
specCombination: string[]; // 每個SKU對應(yīng)的規(guī)格值組合
price: number;
stock: number;
extraParams?: Record<string, any>;
}
const initialState: ProductState = {
basicInfo: {
name: '',
categoryId: 0,
platformCategoryId: 0,
description: ''
},
specs: [],
dynamicAttributes: {},
extraParams: {},
skuList: []
};
Reducer 設(shè)計(包含聯(lián)動邏輯)
type Action =
| { type: 'UPDATE_BASIC_INFO'; payload: Partial<ProductState['basicInfo']> }
| { type: 'UPDATE_SPEC'; payload: { index: number; spec: Partial<ProductState['specs'][0]> } }
| { type: 'SET_PLATFORM_CATEGORY'; payload: { platformCategoryId: number; dynamicAttributes: any; extraParams: any } }
| { type: 'UPDATE_SKU'; payload: SKU[] };
function generateSKUList(specs: ProductState['specs'], extraParams: ProductState['extraParams']): SKU[] {
// 簡化示例:生成規(guī)格組合的笛卡爾積
if (specs.length === 0) return [];
function cartesian(arrays: string[][]): string[][] {
return arrays.reduce<string[][]>(
(a, b) => a.flatMap(d => b.map(e => [...d, e])),
[[]]
);
}
const specValues = specs.map(s => s.values.length ? s.values : ['']);
const combinations = cartesian(specValues);
return combinations.map(comb => ({
specCombination: comb,
price: 0,
stock: 0,
extraParams: { ...extraParams }
}));
}
function productReducer(state: ProductState, action: Action): ProductState {
switch (action.type) {
case 'UPDATE_BASIC_INFO':
return { ...state, basicInfo: { ...state.basicInfo, ...action.payload } };
case 'UPDATE_SPEC':
return produce(state, draft => {
draft.specs[action.payload.index] = { ...draft.specs[action.payload.index], ...action.payload.spec };
draft.skuList = generateSKUList(draft.specs, draft.extraParams);
});
case 'SET_PLATFORM_CATEGORY':
return produce(state, draft => {
draft.basicInfo.platformCategoryId = action.payload.platformCategoryId;
draft.dynamicAttributes = action.payload.dynamicAttributes;
draft.extraParams = action.payload.extraParams;
draft.skuList = generateSKUList(draft.specs, draft.extraParams);
});
case 'UPDATE_SKU':
return { ...state, skuList: action.payload };
default:
return state;
}
}
自定義 Hook 封裝
export function useProductManager() {
const [state, dispatch] = useReducer(productReducer, initialState);
const updateBasicInfo = (payload: Partial<ProductState['basicInfo']>) => {
dispatch({ type: 'UPDATE_BASIC_INFO', payload });
};
const updateSpec = (index: number, spec: Partial<ProductState['specs'][0]>) => {
dispatch({ type: 'UPDATE_SPEC', payload: { index, spec } });
};
const setPlatformCategory = async (platformCategoryId: number) => {
const dynamicAttributes = await fetchDynamicAttributes(platformCategoryId);
const extraParams = await fetchExtraParams(platformCategoryId);
dispatch({
type: 'SET_PLATFORM_CATEGORY',
payload: { platformCategoryId, dynamicAttributes, extraParams }
});
};
const updateSKU = (skuList: SKU[]) => {
dispatch({ type: 'UPDATE_SKU', payload: skuList });
};
return { state, updateBasicInfo, updateSpec, setPlatformCategory, updateSKU };
}
- 組件只調(diào)用 updateXXX 或 setPlatformCategory
- SKU 聯(lián)動邏輯和額外參數(shù)注入都在 reducer 內(nèi)完成
- 避免在組件里寫大量 useEffect
組件使用示例
const ProductPage = () => {
const { state, updateBasicInfo, updateSpec, setPlatformCategory, updateSKU } = useProductManager();
return (
<div>
<BasicInfoForm info={state.basicInfo} onChange={updateBasicInfo} />
<SpecsEditor specs={state.specs} onChange={updateSpec} />
<SKUList skuList={state.skuList} onChange={updateSKU} />
<PlatformCategorySelector
selected={state.basicInfo.platformCategoryId}
onChange={setPlatformCategory}
/>
</div>
);
};
- 各組件只關(guān)注自己的 slice 數(shù)據(jù)
- 不用管其他模塊數(shù)據(jù)的聯(lián)動
- 所有復(fù)雜聯(lián)動邏輯在 hook/reducer 內(nèi)集中處理

總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解基于React.js和Node.js的SSR實(shí)現(xiàn)方案
這篇文章主要介紹了詳解基于React.js和Node.js的SSR實(shí)現(xiàn)方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
React渲染機(jī)制及相關(guān)優(yōu)化方案
這篇文章主要介紹了react中的渲染機(jī)制以及相關(guān)的優(yōu)化方案,內(nèi)容包括react渲染步驟、concurrent機(jī)制以及產(chǎn)生作用的機(jī)會,簡單模擬實(shí)現(xiàn) concurrent mode,基于作業(yè)調(diào)度優(yōu)先級的思路進(jìn)行項(xiàng)目優(yōu)化的兩個hooks,感興趣的小伙伴跟著小編一起來看看吧2023-07-07
前端使用 React Query 管理“服務(wù)器狀態(tài)”的方法
文章介紹了如何安裝和使用React Query來管理服務(wù)器狀態(tài),文章提供了一個實(shí)戰(zhàn)項(xiàng)目示例,展示了如何使用React Query來實(shí)現(xiàn)獲取、新增、刪除和自動刷新Todo列表等功能,感興趣的朋友跟隨小編一起看看吧2025-11-11

