首页 > 解决方案 > 如何在 Vuex 中深度克隆状态并回滚?

问题描述

在 Vuex 中,我想对树中的对象属性进行快照/克隆,对其进行修改,然后可能会回滚到以前的快照。

背景:
在应用程序中,用户可以在应用之前尝试某些更改。应用更改时,它们应该影响主 vuex 树。用户还可以单击«取消»放弃更改并返回到以前的状态。

例子:

state: {
  tryout: {},
  animals: [
    dogs: [
      { breed: 'poodle' },
      { breed: 'dachshund' },
    ]
  ]
}

用户进入»试用«模式并将一个品种从 更改poodlechihuahua。然后她决定要么放弃更改,要么应用它们。

state: {
  animals: [
    dogs: [
      { breed: 'poodle' },
      { breed: 'dachshund' },
    ]
  ],
  tryout: {
    animals: [
      dogs: [
        { breed: 'chihuahua' },
        { breed: 'dachshund' },
      ]
    ]
  }
}

丢弃(回滚到以前的状态):

state: {
  animals: [
    dogs: [
      { breed: 'poodle' },
      { breed: 'dachshund' },
    ]
  ],
  tryout: {}
}

应用(保存主 vuex 树中的更改):

state: {
  animals: [
    dogs: [
      { breed: 'chihuahua' },
      { breed: 'dachshund' },
    ]
  ],
  tryout: {}
}

有什么好的解决方案可以深度克隆状态,对克隆进行更改,然后丢弃或应用更改?这里的示例非常基础,解决方案必须使用更复杂的对象/树。

编辑 1:
有一个名为vuex-undo-redo的库,它基本上记录突变,但有一些问题。在另一个 Stack Overflow 主题中,回到 Vue.js 上的 Undo Redo 等状态,vuex建议使用 vuex 函数replaceState(state)

标签: javascriptvue.jsclonevuexdeep-copy

解决方案


您可以使用JSON.stringify和。JSON.parsereplaceState

在 vuex 中:

const undoStates = [];

// save state
undoStates.push(JSON.stringify(state));

// call state (remove from stack)
if (undoStates.length > 0) {
  this.replaceState(JSON.parse(undoStates.pop()));
}

这将创建整个状态的副本,但您也可以使用存储的一部分:

const animalStates = [];

// save state
animalStates.push(JSON.stringify(state.animals));

// call state (remove from stack)
if (animalStates.length > 0) {
  let animals = JSON.parse(animalStates.pop());
  this.replaceState({...state, animals} );
}

这会将当前状态与您选择的对象(如本例中的动物)合并。


推荐阅读