如何在Zustand中统一更新combinedData,避免多组件重复使用useEffect?
问题描述
我创建了如下Zustand store用于生成派生数据:
import { create } from "zustand"; import myDataStore from "./myDataStore"; type State = { combinedData: any; combineData: () => void; }; const myCombinedData = create<State>((set) => ({ combinedData: [], combineData: () => set(() => { const myData = myDataStore.getState().data; const newCombinedData = myData.df.map((item, index) => { return { ...item, ...myData.df_other[index] }; }); return { combinedData: newCombinedData }; }), })); export default myCombinedData;
这个store依赖另一个存储数据的Zustand store(myDataStore)生成派生数据combinedData。目前在组件中我需要这样调用:
const myData = myDataStore((state) => state.data); const { combinedData, combineData } = myCombinedData(); useEffect(() => { combineData(); }, [myData]);
现在的问题是,多个组件都需要使用combinedData,每个组件都写这段useEffect太冗余,想知道有没有办法在单个位置实现每当myData变化时自动更新combinedData?
解决方案
方法1:在myCombinedData内部订阅myDataStore的变化
直接在myCombinedData内部监听myDataStore的更新,一旦data变化就自动重新计算combinedData,把所有逻辑封装在store内部,组件无需额外处理。
修改后的myCombinedData代码:
import { create } from "zustand"; import myDataStore from "./myDataStore"; type State = { combinedData: any; }; // 抽离计算逻辑,复用性更强 const calculateCombinedData = (data: typeof myDataStore.getState().data) => { return data.df.map((item, index) => ({ ...item, ...data.df_other[index] })); }; const myCombinedData = create<State>((set) => { // 初始化组合数据 const initialData = calculateCombinedData(myDataStore.getState().data); // 订阅myDataStore的data字段变化 const unsubscribe = myDataStore.subscribe( (state) => state.data, (newData) => { set({ combinedData: calculateCombinedData(newData) }); }, { fireImmediately: true } // 确保初始化时触发一次计算 ); // store销毁时自动取消订阅,避免内存泄漏 return { combinedData: initialData, // 可选:如果需要手动触发更新,可保留该方法 // combineData: () => set({ combinedData: calculateCombinedData(myDataStore.getState().data) }) }; }); export default myCombinedData;
组件中直接获取数据即可:
const { combinedData } = myCombinedData();
方法2:封装自定义hook复用逻辑
如果不想改动原有store,可以封装一个自定义hook,把监听和更新逻辑集中在hook里,所有组件直接调用该hook:
import { useEffect } from "react"; import myDataStore from "./myDataStore"; import myCombinedData from "./myCombinedData"; export const useCombinedData = () => { const myData = myDataStore((state) => state.data); const { combinedData, combineData } = myCombinedData(); useEffect(() => { combineData(); }, [myData, combineData]); return combinedData; };
组件中使用方式:
const combinedData = useCombinedData();
内容的提问来源于stack exchange,提问作者Denver Dang
相关产品推荐
相关产品推荐

