【问题标题】:prevent duplicate objects being added to state react redux防止将重复的对象添加到 state react redux
【发布时间】:2018-03-02 17:28:59
【问题描述】:

我有一个关于防止将重复项添加到我的 redux 商店的问题。

这应该是直截了当的,但由于某种原因,我尝试的任何方法都不起作用。

export const eventReducer = (state = [], action) => {

    switch(action.type) {

        case "ADD_EVENT":

            return [...state, action.event].filter(ev => {
                if(ev.event_id !== action.event.event_id){
                   return ev;
                }
            });


        default:
            return state;

    }

};

action 如下所示:

{
   type: "ADD_EVENT",
   event: { event_id: 1, name: "Chelsea v Arsenal" }
}

问题是有时我使用的 API 会通过 websocket 发送相同的消息,这意味着两个相同的事件被添加到我的商店中。

我采取了很多方法,但无法弄清楚如何让它发挥作用。我已经尝试了很多这样的答案,

【问题讨论】:

  • 添加您尝试过的内容是没有得到无用答案的关键。

标签: javascript reactjs ecmascript-6 redux react-redux


【解决方案1】:

为什么你的代码失败了?

代码:

return [...state, action.event].filter(ev => {
    if(ev.event_id !== action.event.event_id){
       return ev;
    }
});

因为先添加新元素,然后过滤相同元素,这样在reducer状态下永远不会添加新值。


解决方案:

使用#array.findIndex检查数组中是否已经存在项,如果不存在则只添加元素,否则返回相同的状态。

这样写:

case "ADD_EVENT":

    let index = state.findIndex(el => el.event_id == action.event.event_id);

    if(index == -1)
        return [...state, action.event];
    return state;

【讨论】:

  • 在我的购物车中,我有一件商品,其中一件包含数量,如果我将相同的商品添加到购物车中,我希望只增加数量item1 => quantity x2 并避免重复
【解决方案2】:

解决办法:

const eventReducer = ( state = [], action ) => {
    switch (action.type) {
        case 'ADD_EVENT':
            return state.some(( { event_id } ) => event_id === action.event.event_id)
                ? state
                : [...state, action.event];
        default:
            return state;
    }
};

测试:

const state1 = eventReducer([], {
    type: 'ADD_EVENT',
    event: { event_id: 1, name: 'Chelsea v Arsenal' }
});

const state2 = eventReducer(state1, {
    type: 'ADD_EVENT',
    event: { event_id: 2, name: 'Chelsea v Manchester' }
});

const state3 = eventReducer(state2, {
    type: 'ADD_EVENT',
    event: { event_id: 1, name: 'Chelsea v Arsenal' }
});

console.log(state1, state2, state3);

【讨论】:

    【解决方案3】:

    您可以使用Array.prototype.find()

    示例 (未测试)

    const eventExists = (events, event) => {
      return evets.find((e) => e.event_id === event.event_id);
    }
    export const eventReducer = (state = [], action) = > {
        switch (action.type) {
        case "ADD_EVENT":
          if (eventExists(state, action.event)) {
            return state;
          } else {
            return [...state, action.event];
          }
        default:
            return state;
        }
    };
    

    更新 (@CodingIntrigue 的评论)

    您也可以使用Array.prototype.some() 获得更好的方法

    const eventExists = (events, event) => {
      return evets.some((e) => e.event_id === event.event_id);
    }
    export const eventReducer = (state = [], action) = > {
        switch (action.type) {
        case "ADD_EVENT":
          if (eventExists(state, action.event)) {
            return state;
          } else {
            return [...state, action.event];
          }
        default:
            return state;
        }
    };
    

    【讨论】:

    • 这是我要采取的方法。除了我将find 替换为some
    • @CodingIntrigue 谢谢你的补充。我更新了答案。
    • @CodingIntrigue 你能解释一下为什么应该使用some 而不是find 吗?
    【解决方案4】:

    在 reducer 中使用数组时需要小心。当您调用时,您实际上是在向列表中添加更多项目:

    [...state, action.event]
    

    如果您改为使用地图,则可以防止重复

    const events = { ...state.events }
    events[action.event.event_id] = action.event.name]
    {...state, events }
    

    【讨论】:

    【解决方案5】:

    对于逻辑部分,您可以这样做,以确保您不会两次获得相同的条目。

    const x = filter.arrayOfData(item => item.event_id !== EVENT_FROM_SOCKET);
    if (x.length === 0) {
      // dispatch action here
    } else {
      // ignore and do nothing
    }
    

    【讨论】:

      猜你喜欢
      • 2012-12-20
      • 1970-01-01
      • 2019-07-05
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多