TypeError:无法分配给 React JS 中的只读属性
2021-01-29
2783
下面是呈现任务数组的 Task 组件。
export function Task() {
const tasks = useSelector((state) => state.tasks.taskArray);
function handleOnDragEnd(result) {
if (!result.destination) return;
let items = [...tasks]; // also tried with tasks.slice() to obtain a deep copy
let i = result.source.index;
let direction = result.destination.index > result.source.index;
// direction true means moving right & swapping
while (i != result.destination.index) {
if (direction) {
let tempGlobalKey = items[i].globalKey;
items[i].globalKey = items[i + 1].globalKey; // <<< here
items[i + 1].globalKey = tempGlobalKey;
i++;
} else {
let tempGlobalKey = items[i].globalKey;
items[i].globalKey = items[i - 1].globalKey; // <<< here
items[i - 1].globalKey = tempGlobalKey;
i--;
}
}
dispatch(updateOrder(items));
}
.
..
... so on
在 taskSlice 中,updateOrder 减速器如下 // 使用 redux-toolkit 因此直接改变下面的状态
export const tasksSlice = createSlice({
name: "tasks",
initialState: {
taskArray: [],
meta: {
globalKey: 0,
completedTaskStartIndex: -1,
},
},
reducers: {
updateOrder: (tasks, { payload }) => {
tasks.taskArray = payload;
},
}
......so on
当拖动结束并处理拖动结束时,错误出现在代码中标记的行上。错误消息是
TypeError: Cannot assign to read only property 'globalKey' of object '#<Object>'
handleOnDragEnd
src/containers/tasks/index.js:60
57 | i++;
58 | } else {
59 | let tempGlobalKey = items[i].globalKey;
> 60 | items[i].globalKey = items[i - 1].globalKey;
| ^ 61 | items[i - 1].globalKey = tempGlobalKey;
62 | i--;
63 | }
我知道状态不能直接改变,因此我正在更新数组的深层副本并将其设置为理想情况下应该可以工作的新状态。如果可以指出问题或者有其他方法可以实现这一点,我将不胜感激。
谢谢。
2个回答
当您使用 Redux 时,reducer 的目的不是改变先前的状态,而是返回一个 新的修改后的 状态。
这听起来像是一个微不足道的区别,但事实并非如此,因为先前的状态对象通常是不可变的,具体取决于框架和/或 Flux 实现。
您可以通过将 Reducer 的代码更改为此代码来使其工作
reducers: {
updateOrder: (previousState, { payload }) => {
return {
...previousState,
taskArray: payload
}
},
}
编辑:
似乎您正在尝试深度克隆嵌套对象。 以下代码
const myNewArray = [...myOldArray];
确实会在内存中使用旧数组中的所有值创建一个新对象,并且改变新对象不会更改旧数组。
有一个小警告,数组中的每个子项都将通过引用而不是值进行克隆。 这意味着执行如下操作:
const myOldArray = [{a: "hello"}]
const myNewArray = [...myOldArray];
将保留对同一
{a: "hello">
对象的引用。
因此,执行
myNewArray.push("asdf")
不会影响
myOldArray
,但执行
myNewArray[0].a = "goodbye"
也会影响
myOldArray
的第一项。
这里有一篇更好的解释文章 https://dev.to/samanthaming/how-to-deep-clone-an-array-in-javascript-3cig
Franco Roura
2021-01-29
全部合而为一...
const copyDeepObject = obj => {
return JSON.parse(JSON.stringify(obj));
}
let copy = copyDeepObject({anything you want to copy});
copy.readOnlyProp = "new value";
Muhammad Ahmar Khan
2023-02-20