在 Javascript 中设置不同状态时如何使 promise 对象不可变?
How to make a promise object immutable when setting different states in Javascript?
我正在使用 React/Redux 并希望使用相同的 Promise 结果来设置两个不同的状态。这是我的代码:
useEffect(() => {
fetchData().then((resp) => {
Object.freeze(resp);
const var1 = resp[0];
const var2 = parseData(resp[0]);
props.setAction1(var1);
props.setAction2(var2);
});
}, []);
resp
的内容是一个字典数组:
Array [ (95) […] ]
0: Array(95) [ {…}, {…}, {…}, … ]
0: Object { date: "6/1/11", open: 21.45673929 }
1: Object { date: "6/2/11", open: 21.02743338 }
2: Object { date: "6/3/11", open: 20.64964196 }
etc...
我知道在 Javascript 中对象是可变的,所以我试图用 Object.freeze(resp)
使 resp
不可变。 var1
应该是字符串日期的结果,var2
应该是日期用parseData
函数转换成Date
对象的结果,其内容是:
function parseData(data) {
data.map((x) => (x.date = new Date(x.date)));
return data;
}
我的问题是,当我运行这个函数时,var1 === var2
。 parseData
函数不仅影响 var2
,而且影响 var1
。我不明白这是怎么发生的,尤其是当我冻结 resp
对象时。这可能是不变性的问题,但我不确定还能去哪里。
我不相信 Object.freeze(resp);
会冻结嵌套对象。您可以尝试以下方法,但我认为它读起来很混乱。
useEffect(() => {
fetchData().then((resp) => {
Object.freeze(resp);
Object.freeze(resp[0]);
const var1 = resp[0];
const var2 = parseData(resp[0]);
props.setAction1(var1);
props.setAction2(var2);
});
}, []);
或者,您可以使用扩展运算符将 parseData
函数更改为 return 副本:
function parseData(data) {
[...data].map((x) => (x.date = new Date(x.date)));
return data;
}
我认为 Object.freeze
不是您要查找的内容。最后,对象仍然引用内存中的相同位置,即使它们被冻结。您应该复制数据以将两者分开,这样您就可以更改其中一个而不影响另一个。
fetchData().then((resp) => {
const ref1 = resp;
/* Alternatively you can also use `Object.assign` */
const ref2 = [ ...resp ].map(obj => ({ ...obj }));
}
就像@JohnD 提到的那样,您也可以在 parseData
函数中执行此操作,这可能会更简洁一些。 ;)
Object.freeze会冻结你传递的对象的直接属性。它不会递归地执行此操作,因此给它一个数组或嵌套对象将不会执行您期望的操作。
The parseData
function affected not only var2
but also var1
.
没有。在这里,var1 === var2
因为您的 parseData
代码根本没有修改对象,而只是其中的一个 属性。它始终是同一个对象实例。当您设置 x.date = new Date(x.date)
时,x
本身不会改变。
不确定这是否有必要,但您可以使用 map()
.
冻结 resp
中的每个单独对象
const freezeAll = items => items.map(item => Object.freeze(item));
const parseData = items => items.forEach(item => item.date = new Date(item.date));
// fetch data, process, and cache it
const data = fetchData().then(parseData).then(freezeAll);
// use data
useEffect(() => {
data.then(items => {
props.setAction1(items[0]);
props.setAction2(items[0]);
});
}, []);
您的 parseData
函数当前 returns 相同的数组对象,其中的对象发生了变化。如果你希望你的对象是不可变的,你不应该有像 x.date =
这样的代码。而是这样做:
function parseData(data) {
return data.map((x) => ({...x, {date: new Date(x.date)} }) );
}
我正在使用 React/Redux 并希望使用相同的 Promise 结果来设置两个不同的状态。这是我的代码:
useEffect(() => {
fetchData().then((resp) => {
Object.freeze(resp);
const var1 = resp[0];
const var2 = parseData(resp[0]);
props.setAction1(var1);
props.setAction2(var2);
});
}, []);
resp
的内容是一个字典数组:
Array [ (95) […] ]
0: Array(95) [ {…}, {…}, {…}, … ]
0: Object { date: "6/1/11", open: 21.45673929 }
1: Object { date: "6/2/11", open: 21.02743338 }
2: Object { date: "6/3/11", open: 20.64964196 }
etc...
我知道在 Javascript 中对象是可变的,所以我试图用 Object.freeze(resp)
使 resp
不可变。 var1
应该是字符串日期的结果,var2
应该是日期用parseData
函数转换成Date
对象的结果,其内容是:
function parseData(data) {
data.map((x) => (x.date = new Date(x.date)));
return data;
}
我的问题是,当我运行这个函数时,var1 === var2
。 parseData
函数不仅影响 var2
,而且影响 var1
。我不明白这是怎么发生的,尤其是当我冻结 resp
对象时。这可能是不变性的问题,但我不确定还能去哪里。
我不相信 Object.freeze(resp);
会冻结嵌套对象。您可以尝试以下方法,但我认为它读起来很混乱。
useEffect(() => {
fetchData().then((resp) => {
Object.freeze(resp);
Object.freeze(resp[0]);
const var1 = resp[0];
const var2 = parseData(resp[0]);
props.setAction1(var1);
props.setAction2(var2);
});
}, []);
或者,您可以使用扩展运算符将 parseData
函数更改为 return 副本:
function parseData(data) {
[...data].map((x) => (x.date = new Date(x.date)));
return data;
}
我认为 Object.freeze
不是您要查找的内容。最后,对象仍然引用内存中的相同位置,即使它们被冻结。您应该复制数据以将两者分开,这样您就可以更改其中一个而不影响另一个。
fetchData().then((resp) => {
const ref1 = resp;
/* Alternatively you can also use `Object.assign` */
const ref2 = [ ...resp ].map(obj => ({ ...obj }));
}
就像@JohnD 提到的那样,您也可以在 parseData
函数中执行此操作,这可能会更简洁一些。 ;)
Object.freeze会冻结你传递的对象的直接属性。它不会递归地执行此操作,因此给它一个数组或嵌套对象将不会执行您期望的操作。
The
parseData
function affected not onlyvar2
but alsovar1
.
没有。在这里,var1 === var2
因为您的 parseData
代码根本没有修改对象,而只是其中的一个 属性。它始终是同一个对象实例。当您设置 x.date = new Date(x.date)
时,x
本身不会改变。
不确定这是否有必要,但您可以使用 map()
.
resp
中的每个单独对象
const freezeAll = items => items.map(item => Object.freeze(item));
const parseData = items => items.forEach(item => item.date = new Date(item.date));
// fetch data, process, and cache it
const data = fetchData().then(parseData).then(freezeAll);
// use data
useEffect(() => {
data.then(items => {
props.setAction1(items[0]);
props.setAction2(items[0]);
});
}, []);
您的 parseData
函数当前 returns 相同的数组对象,其中的对象发生了变化。如果你希望你的对象是不可变的,你不应该有像 x.date =
这样的代码。而是这样做:
function parseData(data) {
return data.map((x) => ({...x, {date: new Date(x.date)} }) );
}