Vuex/Redux存储模式下父子组件差异化数据存储方案咨询
存储模式下多版本API数据的存储方案疑问
我理解存储模式(store pattern)、单一数据源(single source of truth)的价值,也清楚在store action中统一发起API请求比各组件单独请求的优势。我也知道可以通过传入筛选条件调用store action来更新全局store变量,但遇到了父组件需要原始数据、子组件需要另一版本筛选后数据的问题:
有一个人员数据API:
GET api/people返回未筛选的全量人员:['John Smith', 'Joe Bloggs', 'Jane Doe']GET api/people?isOffSick=true返回病假人员:['Jane Doe']
父组件需要全量数据,子组件需要病假人员数据,但API返回结果里没有isOffSick字段,无法通过本地getter筛选,必须发起两次独立请求。
当前的Vuex代码如下:
store.js
export const store = createStore({ state: { people: [] }, actions: { fetchPeople(filters) { // ...拼接queryString逻辑 const res = api.get('/people' + queryString); commit('setPeople', res.data); } }, mutations: { setPeople(state, people) { state.people = people; } } });
parent.vue(需要全量人员)
export default { mounted() { this.fetchPeople(); }, computed: { ...mapState([ 'people' ]) }, methods: { ...mapActions(['fetchPeople']), } }
child.vue(需要病假人员)
export default { mounted() { this.fetchPeople({ isOffSick: true }); }, computed: { ...mapState([ 'people' ]) }, methods: { ...mapActions(['fetchPeople']), } }
现在的问题是,父组件设置的store变量会被子组件覆盖,无法同时满足两者的数据需求。我想知道遵循store核心设计模式的前提下,第二组人员数据应该存在哪里:
- 给每个数据变体单独创建store变量似乎不够优雅
- 存在子组件自身状态又违背了存储模式和无状态组件的设计思路
- 现在陷入了要么创建大量store变量、要么让组件单独请求存储的两难境地
优选解决方案
1. 按筛选键缓存多版本数据到store
修改store的state结构,用一个对象存储不同筛选条件对应的数据集,同时支持缓存避免重复请求:
// store.js export const store = createStore({ state: { peopleCache: {} // 键为筛选条件的字符串化结果,值为对应数据 }, actions: { async fetchPeople({ commit, state }, filters = {}) { const filterKey = JSON.stringify(filters); // 缓存命中则直接返回,避免重复请求 if (state.peopleCache[filterKey]) return; const queryString = new URLSearchParams(filters).toString(); const res = await api.get(`/people?${queryString}`); commit('addPeopleToCache', { key: filterKey, data: res.data }); } }, mutations: { addPeopleToCache(state, { key, data }) { state.peopleCache[key] = data; } }, getters: { getPeopleByFilter: (state) => (filters) => { const filterKey = JSON.stringify(filters); return state.peopleCache[filterKey] || []; } } });
组件通过getter获取对应筛选条件的数据:
// parent.vue computed: { people() { return this.$store.getters.getPeopleByFilter({}); } } // child.vue computed: { sickPeople() { return this.$store.getters.getPeopleByFilter({ isOffSick: true }); } }
这种方式既遵循单一数据源原则,又能高效缓存多版本数据,无需为每个变体单独声明state变量。
2. 拆分store模块(适合复杂业务场景)
如果人员数据的不同变体伴随复杂业务逻辑,可以将人员相关状态拆分为独立命名空间模块,在模块内维护多版本数据缓存,让store结构更清晰:
// store/modules/people.js export default { namespaced: true, state: { cache: {} }, actions: { async fetch({ commit }, filters) { const key = JSON.stringify(filters); if (this.state.cache[key]) return; const res = await api.get(`/people?${new URLSearchParams(filters)}`); commit('CACHE_DATA', { key, data: res.data }); } }, mutations: { CACHE_DATA(state, { key, data }) { state.cache[key] = data; } }, getters: { getByFilter: (state) => (filters) => state.cache[JSON.stringify(filters)] || [] } } // store.js import peopleModule from './modules/people'; export const store = createStore({ modules: { people: peopleModule } });
3. 组件内缓存(非共享数据的妥协方案)
如果某类数据变体仅在单个组件内使用、无跨组件共享需求,可以在组件内发起请求并存储到自身data中。这并没有违背存储模式核心——只有需要跨组件共享的数据才放入全局store,私有数据留在组件内反而能避免全局store冗余。
内容的提问来源于stack exchange,提问作者BorisAtLast
相关产品推荐
相关产品推荐

