嵌套对象在 React 中发生变异
Nested Object mutates in React
我几乎急需帮助。我是一名机械工程师,我正在为我的工作做一种计算器。我有一个问题,我已经花了几周时间。我似乎无法解决它。
为了不让您厌烦冗长的代码,我会尽量概括它。
- 我先给出一个示例代码。
- 然后我将解释预期的行为以及实际发生的情况。
- 最后我会解释一下我到目前为止为解决这个问题所做的努力。
- 我会根据评论在底部添加更多内容,以帮助澄清我的问题。
代码示例
父对象
import {childObject} from "./childObject"
// in my code "childObject" are actually different from each other
const object1 = Object.assign({}, childObject);
const object2 = Object.assign({}, childObject);
const object3 = Object.assign({}, childObject);
const object4 = Object.assign({}, childObject);
const object5 = Object.assign({}, childObject);
const object6 = Object.assign({}, childObject);
const exampleObject = {
name: "foo",
otherInfo: "bar",
nestedObject:{
standardType: [object1, object2, object3],
specialType: [object4, object5, object6]
},
sumfunc(){}
}
子对象
export const childObject = {
name: "I'm losing my mind",
value: "" //<-- this will change
otherInfo: "please help me",
sumfunc(){}
}
解释
我正在做的是:
- 包含所有类型父对象的搜索栏。
- 允许用户select一个或多个相同或不同的父对象。
- 将复制的 selection 存储在 redux 存储中。
- 显示 selection,每个 parentObject 作为一个表单。 [见图]
- 在表单中输入时,嵌套对象的值会改变
现在...问题是当我打开搜索栏和 select 相同的 parentObject,从而复制它时,它的所有值都发生了变化。如上图所示。
我尝试了什么
- 我尝试在 selected parentObject 上使用 lodash clone 和 deepClone。
- 我尝试在 selected childObjects 上使用加载克隆和深度克隆。
- 我已经尝试过,因为对象具有相同的结构,遍历所有键值对并浅拷贝它们。
- 我尝试不通过搜索栏组件将 parentObject 发送到 reducer,而是只发送一个字符串,reducer 本身会将 parentObject 添加到存储中。
我试过的所有方法都没有阻止突变。 deepClone 方法停止了突变,但在 return 中,对象中的函数停止工作(也许我需要以某种方式绑定它?)
更多内容
更新nestedObject值的代码
const inputsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
const formCopy = Object.assign({}, formEQ);
const inputFieldName = e.target.name;
// if anything other than a empty, number or decimal inputted, then return
const isNum = e.target.value.match(/^(?:\d{1,8}(?:\.\d{0,8})?)?$/);
if (!isNum) return;
// Update priority list to calculate the last updated input
formCopy.priorityList = formCopy.priorityList.sort((a, b) => {
if (a === inputFieldName) return 1;
if (b === inputFieldName) return -1;
else return 0;
});
// Update selected input field
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === inputFieldName) {
input.value = e.target.value;
}
return input;
});
// If more than two inputs empty do not calculate
const emptyInputs = formCopy.inputs[calcmode].reduce(
(acc, nV) => (nV.value === "" ? (acc += 1) : acc),
0
);
// Calculate the last edited input field
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === formCopy.priorityList[0] && emptyInputs <= 1) {
const calculatedValue = formCopy.calculate(
formCopy.priorityList[0],
calcmode
);
input.value = Number(calculatedValue).toFixed(2);
}
return input;
});
// Final set hook, now with calculated value
setformEQ({ ...formCopy });
};
请 Whosebug 的好心人...帮帮我!
你的代码有几个问题:
您正在根据子对象的 name
属性 进行过滤,并且它们都具有相同的名称。始终为对象提供唯一性 id
,以便可以轻松区分它们。
你的过滤逻辑大错特错:
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === inputFieldName) {
input.value = e.target.value; // < -- Culprit
}
return input;
});
从不改变内联,始终创建一个新副本。
这就是您的代码 change
函数应有的样子(为清楚起见,我删除了动态键选择):
const change = (e, id) => {
const inputFieldName = e.target.name;
// local copy of array
const nestedArr = [...qform.nestedObject.standardType];
// finding item to be updated
const index = nestedArr.findIndex((i) => i.id === id);
console.log({ index, inputFieldName, e, id });
if (index !== -1) {
const item = nestedArr[index];
item.value = e.target.value;
nestedArr[index] = item;
// deep copy till k depth where k is the key to be updated
const newObject = {
...qform,
nestedObject: {
...qform.nestedObject,
standardType: [...nestedArr],
},
};
setQform(newObject);
}}
检查这个例子:Demo
我几乎急需帮助。我是一名机械工程师,我正在为我的工作做一种计算器。我有一个问题,我已经花了几周时间。我似乎无法解决它。
为了不让您厌烦冗长的代码,我会尽量概括它。
- 我先给出一个示例代码。
- 然后我将解释预期的行为以及实际发生的情况。
- 最后我会解释一下我到目前为止为解决这个问题所做的努力。
- 我会根据评论在底部添加更多内容,以帮助澄清我的问题。
代码示例
父对象
import {childObject} from "./childObject"
// in my code "childObject" are actually different from each other
const object1 = Object.assign({}, childObject);
const object2 = Object.assign({}, childObject);
const object3 = Object.assign({}, childObject);
const object4 = Object.assign({}, childObject);
const object5 = Object.assign({}, childObject);
const object6 = Object.assign({}, childObject);
const exampleObject = {
name: "foo",
otherInfo: "bar",
nestedObject:{
standardType: [object1, object2, object3],
specialType: [object4, object5, object6]
},
sumfunc(){}
}
子对象
export const childObject = {
name: "I'm losing my mind",
value: "" //<-- this will change
otherInfo: "please help me",
sumfunc(){}
}
解释
我正在做的是:
- 包含所有类型父对象的搜索栏。
- 允许用户select一个或多个相同或不同的父对象。
- 将复制的 selection 存储在 redux 存储中。
- 显示 selection,每个 parentObject 作为一个表单。 [见图]
- 在表单中输入时,嵌套对象的值会改变
现在...问题是当我打开搜索栏和 select 相同的 parentObject,从而复制它时,它的所有值都发生了变化。如上图所示。
我尝试了什么
- 我尝试在 selected parentObject 上使用 lodash clone 和 deepClone。
- 我尝试在 selected childObjects 上使用加载克隆和深度克隆。
- 我已经尝试过,因为对象具有相同的结构,遍历所有键值对并浅拷贝它们。
- 我尝试不通过搜索栏组件将 parentObject 发送到 reducer,而是只发送一个字符串,reducer 本身会将 parentObject 添加到存储中。
我试过的所有方法都没有阻止突变。 deepClone 方法停止了突变,但在 return 中,对象中的函数停止工作(也许我需要以某种方式绑定它?)
更多内容
更新nestedObject值的代码
const inputsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
const formCopy = Object.assign({}, formEQ);
const inputFieldName = e.target.name;
// if anything other than a empty, number or decimal inputted, then return
const isNum = e.target.value.match(/^(?:\d{1,8}(?:\.\d{0,8})?)?$/);
if (!isNum) return;
// Update priority list to calculate the last updated input
formCopy.priorityList = formCopy.priorityList.sort((a, b) => {
if (a === inputFieldName) return 1;
if (b === inputFieldName) return -1;
else return 0;
});
// Update selected input field
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === inputFieldName) {
input.value = e.target.value;
}
return input;
});
// If more than two inputs empty do not calculate
const emptyInputs = formCopy.inputs[calcmode].reduce(
(acc, nV) => (nV.value === "" ? (acc += 1) : acc),
0
);
// Calculate the last edited input field
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === formCopy.priorityList[0] && emptyInputs <= 1) {
const calculatedValue = formCopy.calculate(
formCopy.priorityList[0],
calcmode
);
input.value = Number(calculatedValue).toFixed(2);
}
return input;
});
// Final set hook, now with calculated value
setformEQ({ ...formCopy });
};
请 Whosebug 的好心人...帮帮我!
你的代码有几个问题:
您正在根据子对象的
name
属性 进行过滤,并且它们都具有相同的名称。始终为对象提供唯一性id
,以便可以轻松区分它们。你的过滤逻辑大错特错:
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => { if (input.name === inputFieldName) { input.value = e.target.value; // < -- Culprit } return input; });
从不改变内联,始终创建一个新副本。
这就是您的代码 change
函数应有的样子(为清楚起见,我删除了动态键选择):
const change = (e, id) => {
const inputFieldName = e.target.name;
// local copy of array
const nestedArr = [...qform.nestedObject.standardType];
// finding item to be updated
const index = nestedArr.findIndex((i) => i.id === id);
console.log({ index, inputFieldName, e, id });
if (index !== -1) {
const item = nestedArr[index];
item.value = e.target.value;
nestedArr[index] = item;
// deep copy till k depth where k is the key to be updated
const newObject = {
...qform,
nestedObject: {
...qform.nestedObject,
standardType: [...nestedArr],
},
};
setQform(newObject);
}}
检查这个例子:Demo