简体   繁体   English

将 ES6 Map 与 React 和/或 Redux 一起使用

[英]Using ES6 Map with React and/or Redux

I am looking at using the ES6 Map object to do my hashing for me, instead of creating a custom hashing function.我正在考虑使用 ES6 Map对象为我进行散列,而不是创建自定义散列函数。 However, it seems to me that it doesn't have much support for immutability, which is a key thing for React as well as Redux.然而,在我看来,它对不变性的支持并不多,这对于 React 和 Redux 来说都是关键。

I am used to not using any libraries for immutability, but use just plain destructuring:我习惯于不使用任何库来实现不变性,而只使用简单的解构:

const newObj = { ...prevObj, newKey: "value" }

or map/filter with arrays.或使用数组映射/过滤。

However, ES6 Map has methods that directly update the object itself.但是,ES6 Map具有直接更新对象本身的方法。

What I could think of was to do something like this:我能想到的是做这样的事情:

var myMap = new Map()
Var myNewMap = { ...myMap.set() }
this.setState({ myMap:myNewMap })

But I am not sure if that would work.但我不确定这是否可行。

All objects in JavaScript are reference types by nature ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#comparing_objects ). JavaScript 中的所有对象本质上都是引用类型( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#comparing_objects )。 The only reason that the state object in Redux is immutable is because the library itself doesn't let you directly modify the state object return by getState . Redux 中状态对象不可变的唯一原因是库本身不允许您直接修改getState返回的状态对象。

Additionally, a JavaScript object is itself a dictionary, so fetching data from that state object by property name is still O(1) time complexity此外,JavaScript 对象本身就是一个字典,因此通过属性名称从该状态对象中获取数据仍然是 O(1) 时间复杂度

If you just want a type-safe key-value store, you can use the following syntax:如果您只想要一个类型安全的键值存储,您可以使用以下语法:

entities: { [id: number]: MyEntity },
...

I thought about using Map data structure with react +redux recently and decided against it.我最近考虑使用 Map 数据结构和 react +redux 并决定反对它。

Though there is a slight performance benefit, for some use cases, in using the Map, mostly because the compiler knows better what to expect.尽管在某些用例中使用 Map 有一点性能优势,但主要是因为编译器更清楚会发生什么。 And you get a size prop for free :)你会免费获得一个尺寸道具 :)

I think there are more reasons agains this approach:我认为反对这种方法的原因更多:

First of all redux doesn't like non serializable object - faq .首先,redux 不喜欢不可序列化的对象 - faq it won't work if you want to use SSR or save your data in localStorage.如果您想使用 SSR 或将数据保存在 localStorage 中,它将不起作用。

You can't enjoy many features in the redux toolkit, because they assume / create simple object data structures.您无法享受 redux 工具包中的许多功能,因为它们假定/创建简单的对象数据结构。 for example the the createEntityAdapter - which I personally think is great例如createEntityAdapter - 我个人认为很棒

You can create a new map in each reducer, but it might get annoying pretty fast, and I'm not sure about the performance.您可以在每个 reducer 中创建一个新地图,但它可能会很快变得烦人,而且我不确定性能。

React doesn't care that much though :) React 并不太在意 :)

I am using an ES6 in React project that uses Redux as well.我在使用 Redux 的 React 项目中使用 ES6。

use-case #1用例 #1

Within a component: 在一个组件内:

I receive the data, then I need to process it, eg add some flags and/or additional parameters to each of the elements, then I store it within the component as ES6 Map(not in the component state).我收到数据,然后我需要处理它,例如为每个元素添加一些标志和/或附加参数,然后我将它作为 ES6 Map 存储在组件中(而不是组件状态)。

Later when I need to update the data (eg new elements were fetched) I'm using Thunk that sets a loading flag in redux, which, later is back to false which triggers the update.稍后当我需要更新数据时(例如,获取了新元素),我使用 Thunk 在 redux 中设置了一个loading标志,稍后又回到false触发更新。

I update my ES6 Map with new data, mutating it, but not creating a new Map.我用新数据更新我的 ES6 地图,对其进行变异,但没有创建新地图。 My component gets updated because of the loading flag and re-renders with the new data from internal Map我的组件由于loading标志而更新,并使用内部地图中的新数据重新渲染

use-case #2用例 #2

In Redux state 在 Redux 状态

I have an ES6 Map in my Redux state because I want to share it with multiple components.我的 Redux 状态中有一个 ES6 Map,因为我想与多个组件共享它。 I keep it immutable like so in a reducer:我在减速器中保持不变:

 const newMap = new Map(oldMap.entries())

but creating new Map on each update is only useful if you don't update it too often, but do often read from it.但是在每次更新时创建新地图只有在您不经常更新它但经常从中读取时才有用。

In my case I have to use Map in Redux state because ES6 Map is keeping the order of elements while providing O(1) access to them.在我的情况下,我必须在 Redux 状态下使用 Map,因为 ES6 Map 保持元素的顺序,同时提供对它们的 O(1) 访问。

So I'd suggest you to figure out parts where it's beneficial to use ES6 Map and where it's fine to just go along with regular Object .因此,我建议您找出使用 ES6 Map 有益的部分,以及与常规Object一起使用的部分。

It's actually very easy to use ES6's Map within the state.在 state 内使用 ES6 的Map其实非常简单。 You need to use ReactDOM and ReactDOM.render(document.getElementById('someid'), map.get("123"));你需要使用ReactDOMReactDOM.render(document.getElementById('someid'), map.get("123")); . . But for this to have any advantageous benefits in terms of optimization, it's a bit more complicated.但是为了在优化方面有任何有利的好处,它有点复杂。 And it might only be useful for certain applications.它可能只对某些应用程序有用。

To avoid speaking strictly in the abstract, let's take a sample application: the DOM is an HTML <table> and the ReactJS state is a Map of coordinates and values.为了避免过于抽象,让我们来看一个示例应用程序:DOM 是一个 HTML <table> ,而 ReactJS 状态是一个坐标和值的Map The <td> elements would have coordinate IDs, like id="pos-1,2" would be the position of the 1st row, the second column. <td>元素将具有坐标 ID,例如id="pos-1,2"将是第一行第二列的位置。 Now the state could be looking like...现在状态可能看起来像......

this.state = {
    'coordinates': Map({'1,2':'my 1/2 text!', '4,5':'my 4/5 text!'}),
};

To update state, you could have updateState() ...要更新状态,您可以使用updateState() ...

updateState(newmap) {
    const coordinates = this.state.coordinates;
    newmap.keys().forEach((key) => {
        const parent = document.getElementById('pos' + key);
        const text = newmap.$key;
        ReactDOM.unmountComponentAtNode(parent);
        ReactDOM.render(parent, (<span>{text}</span>);
        coordinates.set(key, text);
    });
    this.state.setState({'coordinates':coordinates});
}

So, what is happening in here?那么,这里发生了什么? We could update the state, whenever we want, with any position on the table grid.我们可以随时用表格网格上的任何位置更新状态。 For instance, if we had 500 grids already with text in them, I could add just one more grid text field, with this.updateState(Map({'1000,500':'my text at position 1000x500!'}));例如,如果我们已经有 500 个带有文本的网格,我可以再添加一个网格文本字段,使用this.updateState(Map({'1000,500':'my text at position 1000x500!'})); . . In this way, the Map() can be used within the state and it retains its benefit of an O(1) lookup for a single change, because our updateState() handles it.通过这种方式, Map()可以在状态中使用,并且它保留了 O(1) 查找单个更改的好处,因为我们的updateState()处理它。

This also bypasses much of the use of render() , but that is a design decision.这也绕过了render()的大部分使用,但这是一个设计决定。 I used the example of a 1,000x1,000 table grid, because having 1,000^2 unique, stateful elements has a tremendous load/handling time when using render() , and in that case, Map() would work just fine.我使用了 1,000x1,000 表格网格的示例,因为在使用render()时,拥有 1,000^2 个唯一的、有状态的元素具有巨大的加载/处理时间,在这种情况下, Map()可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM