【问题标题】:Generating and mutating state in vuex在 vuex 中生成和改变状态
【发布时间】:2021-03-05 09:48:23
【问题描述】:

我正在使用 Array() 构造函数创建一个大小为 3 的空数组,然后使用 forEach() 或 Array.fill() 填充它,但是当我尝试更改/改变数组中的任何元素时,任何类似的值另一个数组中的成员设置为分配给任何其他成员的最后一个值。 创建方法:

const createBoard = () => {
  let row = Array(3);
  const cellDS = {
    isClcicked: false,
    toPlayer: null,
    cellID: null,
  };
  row.fill(cellDS);
  let gameBoard = Array(3);
  gameBoard.fill(row);
  console.log("board created");
  return gameBoard;
};

当我更改第一行第一个元素的单元格 ID 时,我得到以下结果:

[[
  { isClicked: false, toPlayer: null, cellID: 1 },
  { isClicked: false, toPlayer: null, cellID: 1 },
  { isClicked: false, toPlayer: null, cellID: 1 },
],
[
  { isClicked: false, toPlayer: null, cellID: 1 },
  { isClicked: false, toPlayer: null, cellID: 1 },
  { isClicked: false, toPlayer: null, cellID: 1 },
],
[
  { isClicked: false, toPlayer: null, cellID: 1 },
  { isClicked: false, toPlayer: null, cellID: 1 },
  { isClicked: false, toPlayer: null, cellID: 1 },
]]

isClicked 和 toPlayer 也是如此。

Vuex 代码:

const state = { gameBoard: [] };
const getters = {
  getGameBoard: (state) => state.gameBoard,
};
const actions = {
  createBoard: ({ commit }) => {
    commit("setBoard");
  },
  editBoard: ({ commit }) => {
    commit("changeBoard");
  },
};
const mutations = {
  setBoard: (state) => {
    state.gameBoard = createBoard();
  },
  changeBoard: (state) => {
    console.log("Before: " + state.gameBoard[0][0]["cellID"]);
    state.gameBoard[0][0]["cellID"] = 1;
    console.log("After: " + state.gameBoard[0][0]["cellID"]);
    console.log("After: " + state.gameBoard[0][1]["cellID"]);
  },
}

解决方案: fill() 在整个应用程序中创建元素的精确静态副本,您不能简单地在空数组上使用 forEach,例如 Array(3) 将返回 [ , , ] ,这本身是没有意义的(不确定的)。 所以你可以用空值填充它,然后在它上面使用 forEach()。

【问题讨论】:

  • 你不能简单地在 [ , , ] 上使用 forEach

标签: arrays vue.js vuejs2 vuex


【解决方案1】:

你需要了解JS中的对象以及值类型和对象类型的区别。在您的情况下,fill 方法只是用相同的对象填充一个数组,如果您更改此对象的某些字段,它会在数组的所有条目中更改,因为这是完全相同的对象。这个数组只存储一个对该对象的引用,而不是它的副本。

如果您希望创建此对象的独立副本,您应该在for 循环中创建它们,以便用对象自己的副本填充数组的每个元素。

for (let ind=0; ind< row.length; ind++) {
  row[ind] = Object.assign({}, cellDS); 
}

请记住,使用Object.assign 您不会复制所有内部对象道具,而只会复制值类型道具。对象类型道具将指向与原始对象中相同的对象。 要制作对象的深层副本,您应该使用lodash 包中的cloneDeep 函数。

【讨论】:

  • 我尝试使用你的 sn-p 但它从 Array(3) 返回了相同的空数组
  • 到目前为止的工作是用 null 填充它们,然后使用 forEach 生成所需的数组 row.fill(null); row.forEach((x, y) => { row[y] = Object.assign({}, cellDS); console.log(x, y, cellDS); });
  • 抱歉,forEach 不考虑数组的空元素。您应该使用简单的for。查看更新的答案
  • 用空值预填充空数组也可以,如果您可以用这个更新答案
  • 如果您希望将数组的长度作为参数传递,那么您应该使用我的解决方案,因为您可以指示空值的动态数量
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-16
  • 2020-03-08
  • 2021-04-10
  • 2020-01-20
  • 1970-01-01
  • 2020-08-13
  • 2021-09-07
相关资源
最近更新 更多