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

时间:2017-04-20 15:40:38

标签: javascript redux vuejs2 flux vuex

我目前正在VueJS中编写应用程序(尤其是Vuex)。但是,我的问题与这个库并没有很强的联系,而是与像flux / redux / Vuex这样的商店有关的架构。

简而言之,我有几个API(每个团队一个API /数据库),对于每个团队/ API,我有几个用户。这些团队和用户由简单对象表示,每个都有自己的slug。重要提示:团队的障碍当然是独一无二的,但slu users用户对于他们自己的团队来说是独一无二的。然后,用户的唯一性约束将是" 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
}

您认为团队不仅拥有用户,我还有许多其他类型的模型,我应该将它们链接在一起。这个方法有效,但我发现它很麻烦(特别是它很简单,我会有很多其他类似的动作)。你对我的架构有什么建议吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

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

如果我们将团队和用户群结合起来以创建唯一标识符怎么办?这是我如何想象您的用户有一个红色团队和一个蓝色团队的情况:

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...
    }
  }
}

API中的每个用户都不需要存在teamSlug属性。您可以在将数据加载到存储区时以自己的突变形式创建它。

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