【问题标题】:Set custom immutablejs keys to prevent data duplication?设置自定义 immutablejs 键以防止数据重复?
【发布时间】:2016-12-07 21:01:14
【问题描述】:

我有以下格式的数据action.places

我只想将它与传入的新数据结合起来,并返回更新地点的新地图。如果我得到一个地点对象并且其中一个地点与前一个地点具有相同的纬度/经度,我不想附加该数据。

{
  places: [
    {
      place: {
        lat: 123,
        lon: 321,
      }
    },
    {
      place: {
        lat: 432,
        lon: 234,
      }
    },
  ]
}

我将如何使用地图执行此操作?目前我正在以这种方式添加,但所有内容都是重复的,我找不到非混乱的解决方案:

case RECEIVE_PLACES:
  return state
    .set('places', state.get('places').update(fromJS(action.places)))

理想情况下,我会将每个 obj 的键设置为 [${lat},${lon}](唯一标识地点的方式),这样我只需遍历键即可获得我的地点。

【问题讨论】:

  • 基于此描述,我认为您应该考虑使用Set 而不是List 来存储“地点”。
  • 我使用的是Map。 @Josep - 我更新了问题。
  • 不,你不是。你在顶层,但是“places”是一个列表,这是因为fromJS 默认情况下会将一个数组转换为一个列表。
  • 嗯,从这个意义上说是的,然后是的 - 我想占据每个地方并将其添加到地图中,使用 lat/lon 的组合作为每个地方的键。
  • 我的建议是,如果不使用List 来存储您使用Set 的地方,您就不会遇到这个问题,因为它不允许重复存在。有两种方法可以实现这一点,通过使用 fromJS 函数的其他参数,以便它进行您想要的转换,或者您手动进行。如果你愿意,我可以在答案中给你那个代码。你有兴趣还是不想要一套?我的意思是,如果项目的顺序与你无关,你真的应该使用 Set :-)

标签: javascript reactjs redux immutability immutable.js


【解决方案1】:

你可以过滤掉重复的地方项

case RECEIVE_PLACES:  {
  const newPlaces = fromJS(action.places).filter((newItem) => (
    !state.get('stores').find((oldItem) => (
      oldItem.place.lat === newItem.place.lat &&
      oldItem.place.lon === newItem.place.lon
    )
  );

  return state.set('stores', state.get('stores').update(newPlaces));
}

【讨论】:

  • 使用 lat 和 lon 作为键怎么样?这种方式似乎有点绕。
  • @eveo 你可以做到这一点,但你正在改变数据的架构,我给出的解决方案在性能上也不逊色。
  • 你给了我一个与我之前的问题相同的解决方案,我现在采取了不同的方法,所以很明显架构会改变。
  • 如果你想改变你从 api 接收到的对象的模式,这取决于你。我个人觉得这是一种不好的做法,因为您必须撤消您的架构更改才能将对象作为有效负载传递给您的其他 CRUD API。
  • 啊,我不是说响应模式,我的意思是我将这些数据按摩成新数据的格式自我上一个问题以来发生了变化,在客户端,重写它以使用它是微不足道的接收新数据并将其与旧数据组合时我想形成的新对象“模式”。
【解决方案2】:

如果您使用 Immutable.Set 而不是 Immutable.List 来持久化位置,那么一切都会变得更容易,性能也会更好。

所以,如果在你的减速器中你做了类似的事情:

import { Map, Set, fromJS } from 'immutable';

const initialState = new Map([
  ['places', new Set()],
  // Whatever other props that Map has
]);

const yourReducer = (state = initialState, { type, places }) => {
  switch (type) {
    RECEIVE_PLACES:
      return state.update('places', places => places.merge(
        new Set(fromJS(places))
      );
    default:
      return state;
  }
};

你应该没事的。

让我知道这是否适合你。

【讨论】:

  • 我没有收到places => places.merge()。我无权访问这样的“地方”,但是 action.places。同样在 initialState 中,为什么用方括号括起来?为什么不places: new Set()。此外,我正在返回状态并将其他内容设置为状态,因此它也需要在 set 调用中。
  • 在我提供的代码中,我解构了动作,在参数中,注意这一行的结尾const yourReducer = (state = initialState, { type, places }) ?这就是 ES6 解构。如果您查看 Immutable.Map 的文档,您会注意到在初始化新 Map 时,您应该传递一个带有元组的数组。每个元组应该在第一个位置有键,在第二个位置有值。
  • 嗯,是的,是有道理的。我还是不明白。我要action.places => action.places.merge(Set(fromJS(action.places))) Whaaaaat 吗?
  • 不,不,不...动作应该总是有一个普通的javascript对象,你的状态是不可变的。因此,如果您不进行解构,则只需执行state.update('places', places => places.merge(Set(fromJS(action.places)))。或者也许:state.update('places', places => places.merge(Set(fromJS(action.places.places)))。取决于 action.places 是否看起来像这样:{ places: [{ place: { lat: 123, lon: 321, } }] } 或像这样 [{ place: { lat: 123, lon: 321, } }]
  • 所以,如果 action.places 是一个数组,则执行 state.update('places', places => places.merge(Set(fromJS(action.places))) 否则,如果数组在 action.places.places 中,则执行:state.update('places', places => places.merge(Set(fromJS(action.places.places)))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2022-01-10
相关资源
最近更新 更多