React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > react中多个页面,数据相互依赖reducer

react中多个页面,数据相互依赖reducer问题及解决

作者:初遇你时动了情

文章介绍了一个电商商品管理页面的复杂状态管理场景,使用useReducer或useImmerReducer来集中管理状态,避免组件间直接监听,简化联动逻辑,防止死循环,并便于维护和扩展

场景

典型的电商商品管理页面复杂状态场景,涉及多个模块数据联动、动态生成 SKU、属性和额外参数注入等。关键点是 避免组件之间直接相互监听,保持逻辑集中化

页面模块

切换平台分类 → 获取动态属性、额外参数 → 注入到 SKU

修改规格名称 → 重新生成 SKU

核心问题:

useReducer(或者 useImmerReducer) 比直接在组件里用一堆 useState + useEffect 更适合,原因如下:

状态设计

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>; // 平台分类动态属性
  extraParams: Record<string, any>;       // 平台分类额外参数
  skuList: SKU[];
}

interface SKU {
  id?: string;
  specCombination: string[]; // 每个SKU对应的规格值组合
  price: number;
  stock: number;
  extraParams?: Record<string, any>;
}

const initialState: ProductState = {
  basicInfo: {
    name: '',
    categoryId: 0,
    platformCategoryId: 0,
    description: ''
  },
  specs: [],
  dynamicAttributes: {},
  extraParams: {},
  skuList: []
};

Reducer 设计(包含联动逻辑)

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[] {
  // 简化示例:生成规格组合的笛卡尔积
  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 };
}

组件使用示例

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>
  );
};

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文