React:将状态设置为 es6 Map

IT技术 javascript reactjs dictionary
2021-05-22 09:31:11

这更像是一个通用的最佳实践问题。

我一直在到处玩 JavaScript Maps,并一直试图找到更多关于将状态属性设置为 Map 是否被认为是反模式/代码气味的信息。下面的链接是 Redux 存储库中的一个问题线程,其中包含一些评论,例如:

“您可以使用 Maps 和 Sets 作为状态值,但由于可序列化问题,不推荐使用。”

然而,这个线程是关于 Redux 的。原版 React 怎么样?任何人有任何强烈的意见或见解?对不起,如果这个问题在错误的地方。

https://github.com/reduxjs/redux/issues/1499

2个回答

如果您不想使用不可变库,您可以在更改时创建一个新 Map:

const [someMap, setSomeMap] = useState(new Map());

当您需要更新它时:

setSomeMap(new Map(someMap.set('someKey', 'a new value'));

同样的概念适用于 Redux:

case 'SomeAction':
  return {
    ...state,
    yourMap: new Map(state.yourMap.set('someKey', 'a new value'))
  }

关于可串行化,它不是本地状态的问题。不过,拥有一个可序列化的 Redux 存储是一种很好的做法。

我可以在我的商店状态中放置函数、Promise或其他不可序列化的项目吗?

强烈建议您只将普通的可序列化对象、数组和原语放入您的商店。从技术上讲,可以将不可序列化的项目插入存储中,但这样做会破坏存储内容的持久化和再水化能力,并干扰时间旅行调试。

如果您对持久性和时间旅行调试等可能无法按预期工作的事情感到满意,那么完全欢迎您将不可序列化的项目放入您的 Redux 存储中。归根结底,这是您的应用程序,您如何实现它取决于您。与 Redux 的许多其他事情一样,请确保您了解所涉及的权衡。

不幸的是,您可以看到 JSON.stringify 不适用于地图:

console.log(JSON.stringify(
  new Map([['key1', 'value1'], ['key2', 'value2']])
))

如果您可以在序列化过程之间进行,则可以使用Array.from

console.log(JSON.stringify(
  Array.from(new Map([['key1', 'value1'], ['key2', 'value2']]))
))

React 状态应该是不可变的,因为 React 使用浅比较来检查相等性。在比较标量值(数字、字符串)时,它会比较它们的值。当比较对象时,它不比较它们的属性——只比较它们的引用(例如“它们是否指向同一个对象?)。

ES6 Maps不是一成不变的,并且针对可变性进行了优化,这就是为什么不建议在 React 中按原样使用它们的原因。React 不会知道地图是否更新。

var map1 = new Map();
var map2 = map1.set('b', 2); // mutate map
map1 === map2; // true because reference remains unchanged after mutation

如果需要,您可以使用 Maps,但您需要使用一些不变性助手,例如Immutable.js. 以下示例使用不可变映射

const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 2); // Set to same value
map1 === map2; // true
const map3 = map1.set('b', 4); // Set to different value
map1 === map3; // false

参考:

https://github.com/reduxjs/redux/issues/1499#issuecomment-194002599

https://stackoverflow.com/a/36084891/2073920