Vuex - 在 api 调用之前或之后提交状态更改?

Vuex - commit state changes before or after api calls?

我是 Vue 和 Vuex 的新手,我仍然不明白 crystal 我应该在异步事件期间什么时候提交状态更改?

Actions 是应该调用异步操作和修改器的地方。但是,在一个动作中,我应该在异步操作之前先调用 mutator(比方说 api 调用来保存数据),还是应该先调用 api 并在它的成功回调中调用将数据更改提交到状态的更改器。

谢谢。如果有人可以向我推荐有关此概念的文章,也会非常有帮助。

* 关于我的问题的更多细节 *

给定以下模型,其中一个预算可以有多个预算类别

state.budgets = {
  1: {
    month: 'October',
    budgetCategories: {
      1: {
        id: 1,
        name: 'Grocery',
        budgeted: 350
      },
      2: {
        id: 2,
        name: 'Rent',
        budgeted: 1000
      },
      3: {
        id: 3,
        name: 'Utilities',
        budgeted: 150
      }
    },
    2: {
      month: 'November',
      budgetCategories: {
        1: {
          id: 1,
          name: 'Grocery',
          budgeted: 350
        },
        2: {
          id: 2,
          name: 'Rent',
          budgeted: 1000
        },
        3: {
          id: 3,
          name: 'Entertainment',
          budgeted: 100
        },
        4: {
          id: 4,
          name: 'Tuition',
          budgeted: 15000
        }
      }
    },
    ...
  }
}

假设我们要更新一个月的特定预算类别,如下所示: state.budgets[target.key].budgetCategories[target.categoryId].budgeted = 200

我们有两种方法可以做到这一点:

  1. 在调用 api 和 mutator 之前先深度复制模型:

// mutation.js

UPDATE_BUDGET_CATEGORY(state, payload) {
    state.budgets[payload.budget.id].budgetCategories[payload.budgetCategory.id] = payload.budgetCategory
}

// action.js
export const updateBudgetCategory = ({
  commit,
  dispatch,
  getters
}, data) {
  // deep copy the model
  let budget = { ...getters.getBudgetById(data.budget.id)
  }
  const newBudget = data.budgetCategory.budgeted
  const oldBudget = budget.budgetCategories[data.budgetCategory.id].budgeted

  if (oldBudget !== newBudget) {
    // update the model
    budget.budgetCategories[data.budgetCategory.id].budgeted = newBudget

    // api call to save the updated model
    return api.updateBudget(budget).then(
      response => {
        // commit to store state
        commit('UPDATE_BUDGET_CATEGORY', data)
      },
      error => {
        // don't commit
        console.log(error.message)
      }
    )
  }
}

优点:这是正确的顺序。 store state中的数据与数据库中的数据是一致的。

缺点:每次更新对象时都必须深拷贝模型。此外,更新深度克隆模型的代码与修改器中的代码基本相同。绝对看起来是多余的而不是干的。

  1. 先提交数据更改,然后从状态中检索模型以将其提交到数据库:

// action.js
export const updateBudgetCategory = ({
  commit,
  dispatch,
  getters
}, data) {
  // deep copy the model
  const newBudget = data.budgetCategory.budgeted
  const oldBudget = getters.getBudgetById(data.budget.id).budgetCategories[data.budgetCategory.id].budgeted

  if (!oldBudget !== newBudget) {
    commit('UPDATE_BUDGET_CATEGORY', data)
    //api call to save the updated model from the state
    return api.updateBudget(getters.getBudgetById(data.budget.id))

  }
}

优点:代码干净整洁。我们告诉 mutator 发生了什么,它负责更新状态。

缺点:那么api调用失败怎么办? Vuex 中有内置的 revert-commit 吗?

如果您要更新的状态取决于异步调用结果,那么显然您需要等待调用完成并提交结果。

如果与异步调用结果无关,则可以立即提交。