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

Aur*_*ret 5 javascript flux redux vuex vuejs2

我目前正在VueJS(尤其是Vuex)中编码应用程序。但是,我的问题与该库的联系并不紧密,而是与flux / redux / Vuex这样的商店拥有的体系结构紧密相关。

简单来说,我有几个API(每个团队一个API /数据库),每个团队/ API有几个用户,这些团队和用户由简单的对象表示,每个都有自己的子对象。重要说明:团队的成员当然是唯一的,但是团队的用户对于他们自己的团队而言是唯一的。用户的唯一性约束将为“ teamSlug / userSlug”。考虑到大量用户,我不能简单地加载所有团队的所有用户。

我的问题是如何正确构造我的应用程序/存储,以恢复给定用户数据块(与他的团队)的数据:如果我尚未加载此用户,请发出API请求以对其进行检索。当前,我已经创建了一个返回用户对象的吸气剂,该对象从用户和团队中获得了胜利。如果返回“ 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
}
Run Code Online (Sandbox Code Playgroud)

您可以想象一个团队不仅有用户,而且我有许多其他类型的模型,我应该将它们链接在一起。此方法有效,但是我发现放置它非常麻烦(特别是这很简单,我将有很多其他此类操作)。您对我的体系结构有什么建议吗?

谢谢!

Tra*_*ohl 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...
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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
      ])
    ]
  },

  // ...
}
Run Code Online (Sandbox Code Playgroud)

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

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
  }
}
Run Code Online (Sandbox Code Playgroud)

Redux 有一篇关于标准化的很棒的文章,我总是会回来阅读:https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape#designing-a-normalized-state