Vue.js + Vuex:如何改变嵌套项的状态?

Vue.js + Vuex: How to mutate nested item state?

假设我有以下树:

[
    {
        name: 'asd',
        is_whatever: true,
        children: [
            {
                name: 'asd',
                is_whatever: false,
                children: [],
            },
        ],
    },
],

树通过 Vuex 在键 'tree' 下存储在模块中,并使用以下称为 'recursive-item' 的递归组件循环:

<li class="recursive-item" v-for="item in tree">
    {{ item.name }}

    <div v-if="item.is_whatever">on</div>
    <div v-else>off</div>

    <ul v-if="tree.children.length">
        <recursive-item :tree="item.children"></recursive-item>
    </ul>
</li>

现在我想切换项目的 属性 'is_whatever',所以我附加了一个监听器

    <div v-if="item.is_whatever" 
         @click="item.is_whatever = !item.is_whatever">on</div>
    <div v-else>off</div>

当我点击它时,它可以工作,但发出以下内容

"Error: [vuex] Do not mutate vuex store state outside mutation handlers."
[vuex] Do not mutate vuex store state outside mutation handlers.

我应该如何在没有这个错误的情况下实现它?我看不出如何将动作或事件发送到树的顶部,因为它是嵌套和递归的,所以我没有到特定项目的路径,对吗?

现在您正在通过调用 item.is_whatever = !item.is_whatever 直接更改状态对象,您需要做的是创建一个变异函数来为您执行该操作以保证适当的反应性:

const store = new Vuex.Store({
  state: { /* Your state */ },
  mutations: {
    changeWhatever (state, item) {
      const itemInState = findItemInState(state, item); // You'll need to implement this function
      itemInState.is_whatever = !item.is_whatever
    }
  }
})

然后您需要在您的视图中将 this.$store.commit('changeWhatever', item) 公开为将由点击触发的操作。

在那天晚上晚些时候咨询了其他一些开发人员之后,我们找到了实现它的几种方法。因为数据嵌套在树中并且我以递归方式访问节点,所以我需要获取特定节点的路径,例如将节点的索引作为 属性 传递,然后添加子节点索引,同时递归地在每个节点中重复该操作,或者仅传递节点的 id,然后 运行 操作中的递归循环以切换其属性。

更优的解决方案可能是扁平化数据结构,从而避免递归的需要。然后可以通过 id 直接访问该节点。

有一个有争议的解决方案,但我就把它留在这里。

州:

state: {
  nestedObject: {
    foo: {
      bar: 0
    }
  }
}

有 Vuex 突变:

mutateNestedObject(state, payload) {
  const { callback } = payload;
  callback(state.nestedObject);
},

这是在组件中使用的示例:

this.$store.commit('mutateNestedObject', {
  callback: (nestedObject) => {
    nestedObject.foo.bar = 1;
  },
});