VueX:如何使用嵌套对象构建我的商店

Posted

技术标签:

【中文标题】VueX:如何使用嵌套对象构建我的商店【英文标题】:VueX: How to architecture my store with nested objects 【发布时间】:2017-09-17 08:36:34 【问题描述】:

我目前正在用 VueJS(尤其是 Vuex)编写一个应用程序。但是,我的问题与这个库没有密切的联系,而是与 Flux/redux/Vuex 之类的商店所具有的架构有关。

简单地说,我有几个 API(每个团队一个 API/数据库),对于每个团队/API,我有几个用户。这些团队和用户由简单的对象表示,每个都有自己的 slug。重要提示:团队的 slug 当然是独一无二的,但 slug 用户对于他们自己的团队来说是独一无二的。用户的唯一性约束将是“teamSlug/userSlug”。并且鉴于用户数量众多,我无法简单地加载所有团队的所有用户。

我的问题是如何正确构建我的应用程序/存储以恢复给定用户 slug 的数据(与他的团队):如果我尚未加载此用户,请发出 API 请求以检索它。目前,我创建了一个返回用户对象的 getter,它从用户和团队那里获取 slug。如果它返回“null”或“.loading”为“false”,我必须运行“loadOne”操作来检索它:

import * as types from '../../mutation-types'
import users from '../../../api/users'

// initial state
const state = 
  users: 


// getters
const getters = 
  getOne: state => (team, slug) => (state.users[team] || )[slug] || null


// actions
const actions = 
  loadOne ( commit, state ,  team, slug ) 
    commit(types.TEAM_USER_REQUEST,  team, slug )
    users.getOne(team, slug)
      .then(data => commit(types.TEAM_USER_SUCCESS,  team, slug, data ))
      .catch(error => commit(types.TEAM_USER_FAILURE,  team, slug, error ))
  


// mutations
const mutations = 
  [types.TEAM_USER_REQUEST] (state,  team, slug ) 
    state.users = 
      ...state.users,
      [team]: 
        ...(state.users[team] || ),
        [slug]: 
          loading: true,
          error: null,
          slug
        
      
    
  ,

  [types.TEAM_USER_SUCCESS] (state,  team, slug, data ) 
    state.users = 
      ...state.users,
      [team]: 
        ...(state.users[team] || ),
        [slug]: 
          ...data,
          slug,
          loading: false
        
      
    
  ,

  [types.TEAM_USER_FAILURE] (state,  team, slug, error ) 
    state.users = 
      ...state.users,
      [team]: 
        ...(state.users[team] || ),
        [slug]: 
          slug,
          loading: false,
          error
        
      
    
  


export default 
  namespaced: true,
  state,
  getters,
  actions,
  mutations

您想象一个团队不仅有用户,我还有许多其他类型的模型,我应该将它们链接在一起。这种方法有效,但我觉得实施起来相当麻烦(特别是它是一个简单的get,我会有很多其他此类操作)。您对我的架构有什么建议吗?

谢谢!

【问题讨论】:

【参考方案1】:

我发现保持 Vuex 存储灵活的最佳方法是对其进行规范化并尽可能保持数据项平坦。这意味着将所有用户存储在一个结构中,并找到一种唯一标识他们的方法。

如果我们将团队和用户 slug 结合起来创建一个唯一标识符会怎样?以下是我想象的红队和蓝队的用户:

const state = 
  users: 
    allTeamSlugs: [
      'blue1',
      'blue2',
      'blue3',
      'red1',
      'red2',
      // etc...
    ],
    byTeamSlug: 
      blue1: 
        slug: 1,
        team: 'blue',
        teamSlug: 'blue1'
      ,
      // blue2, blue3, etc...
      red1: 
        slug: 1,
        team: 'red',
        teamSlug: 'red1'
      ,
      // red2, etc...
    
  

并且teamSlug 属性不需要为您的 API 中的每个用户都存在。当您将数据加载到存储中时,您可以在突变中创建它。

const mutations = 
  [types.TEAM_USER_SUCCESS] (state,  team, slug, data ) 
    const teamSlug = [team, slug].join('')
    state.users.byTeamSlug = 
      ...state.users.byTeamSlug,
      [teamSlug]: 
        ...data,
        slug: slug,
        team: team,
        teamSlug: teamSlug
      
    
    state.users.allTeamSlugs = [
      ...new Set([ // The Set ensures uniqueness
        ...state.users.allTeamSlugs,
        teamSlug
      ])
    ]
  ,

  // ...

那么你的吸气剂可能会像这样工作:

const getters = 
  allUsers: state => 
    return state.users.allTeamSlugs.map((teamSlug) => 
      return state.users.byTeamSlug[teamSlug];
    );
  ,
  usersByTeam: (state, getters) => (inputTeam) => 
    return getters.allUsers.filter((user) => user.team === inputTeam);
  ,
  getOne: state => (team, slug) =>  // or maybe "userByTeamSlug"?
    const teamSlug = [team, slug].join('');
    return state.users.byTeamSlug[teamSlug]; // or undefined if none found
  

Redux 有一篇关于规范化的精彩文章,我总是发现自己会回到:https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape#designing-a-normalized-state

【讨论】:

以上是关于VueX:如何使用嵌套对象构建我的商店的主要内容,如果未能解决你的问题,请参考以下文章

如何循环遍历传递给具有 Vuex 存储和计算属性的组件的对象数组?

如何清除 vuex 商店中的状态?

问:使用 Vue 3 和 typescript(使用 cli 构建的项目)使 vuex 存储在全球范围内可用 +已解决

vuex 商店在开发服务器中工作,但在生产构建中不工作

如何在 natviescript-vue vuex 商店操作中使用 $navigateTo?

Vue,vuex:如何使用命名空间存储和模拟对组件进行单元测试?