不使用突变直接改变 Vuex 状态

Posted

技术标签:

【中文标题】不使用突变直接改变 Vuex 状态【英文标题】:Mutate Vuex state directly without using mutations 【发布时间】:2021-09-11 04:41:54 【问题描述】:

我是来react/reduxvue 的,在学习vuex 的过程中,我发现我可以直接改变状态,并且状态变化仍然会反映在使用它的其他组件上。

Redux 禁止这种行为,如果我直接改变状态,其他组件将不会收到有关这些更改的通知,因此我们必须为此使用操作和减速器。

所有这些方法基本上都提供相同的结果。

methods: 
    IncrementDirect () 
      // mutates the state directly
      this.$store.state.counter += 2;
    ,
    incrementDispatch() 
      // mutates the state inside actions
      this.$store.dispatch("handleIncrement", 2);
    ,
    incrementCommit() 
      // mutates the state inside mutations
      this.$store.commit("increment", 2);
    ,
  ,

我的问题是为什么允许这种行为,以及如果我们可以在应用程序中的任何位置改变状态,为什么我们必须使用 mutations

【问题讨论】:

设置你的存储使用strict mode(用于非生产版本)。至于“为什么”,你大概应该问问原开发者 【参考方案1】:

我认为行为可能已经改变,并且反应性仍然有效,而不需要使用突变。

但我无法找到明确的证据。

随着最近引入反应性和proxy objects(Vuex4/Vue3 充分利用),在处理程序设置函数中包含“提交”代码听起来是一项相当简单的任务。 我相信这就是他们最终所做的,我找到的最接近解释的是pinia。

我很确定在 Vue2/Vuex3 中,直接更新状态会失败。

【讨论】:

【参考方案2】:

从 Redux 到 Vuex 的不同之处在于状态更改不会创建新状态。 Vue 假装不可变,但为了性能,实际上会改变状态并通过反应通道跟踪突变。这是一个巧妙的技巧,但正如您所发现的,它有一些轻微的副作用。

当您直接更改状态时,例如通过组件或操作,您并没有使用那些官方的突变通道。我已经调试了看起来像这样工作的代码,但后来发现了错误,因为反应性并没有完全发挥作用并且没有发生更新。

还应该提到的是,通过 Vue 开发工具调试 Vuex,非常方便,除非你使用突变,否则不会显示任何状态变化。此外,如果您有任何 Vuex 插件,除非发生突变,否则它们不会执行。

除了所有这些看起来有点模糊的技术原因之外,我觉得有必要指出这绝对不是状态变化的通量框架的方式。来自 React 世界,你知道状态变化应该在一个大循环中发生;在 Redux 中,组件调用 action,它调用 reducer 来返回一个新状态,然后应用该状态,应用程序被重新渲染并准备好从组件中进行另一次更改。该框架强制该命令将 UI 与状态分离(尽管我认为这不是一个好主意)并确保所有状态更改都发生在一个地方。 Vuex 突变也是如此 - 这是所有状态变化都应该发生的地方。

将其作为事物的当前状态(双关语不是有意的)推过去,应该注意的是,您可以在 Vue 3 中做一些非常有趣的事情。其中之一是您可以在 Vue 组件之外创建一个响应式对象,将该对象作为全局状态导入到您的组件中,然后随心所欲地对其进行变异。 Vue 3 将使这些突变与整个应用程序保持同步,并且通过一些计划,它可以成为一个非常强大的 Vuex 替代品。

紧随其后的是,下一个 Vuex 看起来可能会抛弃单独突变的概念,并且可以通过动作或其他方式直接改变你的所有状态。我敢打赌,它会使用上面描述的 Vue 3 反应性系统,结合 Vuex 的模块组织思想来制作一个非常简单的框架。

总而言之,你的直觉对于前进的方向是正确的,但对于今天来说可能还为时过早。

【讨论】:

【参考方案3】:

动作是异步的,而突变不是

export default new Vuex.Store(
  state: 
    // put variables and collections here
  ,
  mutations: 
    // put synchronous functions for changing state e.g. add, edit, delete
  ,
  actions: 
    // put asynchronous functions that can call one or more mutation functions
  
)

养成永远不要直接提交突变的习惯。始终使用 Actions 提交您的变更

相关问题: Vuex Action vs Mutations、Is it bad to commit mutations without using actions in Vuex?、Direct manipulation of state within a Vuex action vs. using 'commit' and 'getters'

【讨论】:

以上是关于不使用突变直接改变 Vuex 状态的主要内容,如果未能解决你的问题,请参考以下文章

不要在突变处理程序之外改变 vuex 存储状态

Vuex 突变引发错误 - 不要在突变处理程序之外改变 vuex 存储状态

vuex 错误 - 不要在突变处理程序之外改变 vuex 存储状态

Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)

Nuxt / Vue - 不要在突变处理程序之外改变 vuex 存储状态

nuxt vuex:不要在突变处理程序之外改变 vuex 存储状态