Redux reducer,检查状态数组中是不是存在值并更新状态

Posted

技术标签:

【中文标题】Redux reducer,检查状态数组中是不是存在值并更新状态【英文标题】:Redux reducer, check if value exists in state array and update stateRedux reducer,检查状态数组中是否存在值并更新状态 【发布时间】:2016-06-17 18:50:35 【问题描述】:

所以我有一个数组chosenIds[],它基本上包含一个ids (numbers) 的列表。但我无法访问减速器中的状态以检查 ID I parsed to my action 是否在数组中。

  const initialState = 
  'shouldReload': false,
  'chosenIds': [],
;

export default function filter(state = initialState, action) 
  switch (action.type) 


 case ADD_TYPE:
      console.log(state.chosenIds, "Returns undefined???!!!");

      // Check if NUMBER parsed is in state
      let i = state.chosenIds.indexOf(action.chosenId);

      //If in state then remove it
      if(i) 
        state.chosenIds.splice(i, 1);
        return 
          ...state.chosenIds,
          ...state.chosenIds
        
      
      // If number not in state then add it 
      else 
        state.chosenIds.push(action.chosenId)
        return  ...state.chosenIds, ...state.chosenIds 
      

我不确定发生了什么...但是当我登录state.chosenIds 时,它返回未定义?它甚至不返回初始的空数组 []

基本上这个函数要做的是检查action.chosenId是否在state.chosenIds中,如果是,则删除action.chosenId值,如果不是,则将action.chosenId添加到国家。

【问题讨论】:

这意味着它已经通过了一个状态,但该状态不包含键“chosenIds”。你能告诉我们你是如何调度动作的吗? 状态对象的其余部分是什么样的? 【参考方案1】:

我在这里看到了一些不同的问题。

首先,您在已处于该状态的阵列上使用splice()push()。那是直接突变,它破坏了 Redux。您需要制作数组的副本,然后修改该副本。

其次,对象传播的使用看起来不正确。您正在使用它,就好像“chosenIds”是一个对象,但它是一个数组。此外,您正在复制点差。这导致返回的状态不再具有名为“chosenIds”的字段。

第三,如果没有找到 Array.indexOf() 则返回 -1,这实际上算作“真实”,因为它不是 0。因此,当前的 if/else 不会按您的预期执行。

我会将你的 reducer 改写成如下所示:

export default function reducer(state = initialState, action) 
    switch(action.type) 
        case ADD_TYPE:
            let idAlreadyExists = state.chosenIds.indexOf(action.chosenId) > -1;
            // make a copy of the existing array
            let chosenIds = state.chosenIds.slice();

            if(idAlreadyExists) 
                chosenIds = chosenIds.filter(id => id != action.chosenId);                
                 
            else 
                // modify the COPY, not the original
                chosenIds.push(action.chosenId);            
                  

            return 
                // "spread" the original state object
                ...state,
                // but replace the "chosenIds" field
                chosenIds
            ;
        default:
            return state;
        

【讨论】:

啊当然……我完全忘记了。我不明白为什么你不能直接更新状态?可能只是一个 redux 规则角色 因为对象和数组在 javascript 中是通过引用传递的。当你改变你的状态时,你改变了先前的状态并使先前的状态与新的状态相同。因此 react-redux 不能再检测到新旧之间的变化,所以它不会更新。 除此之外,Redux 至少有两个地方进行浅层相等检查:在 reduce 调用结束时查看状态树的顶部,以及在 React-Redux 中比较返回值用于 mapStateToProps 以查看它们是否已更改。在这两个地方,如果旧值与新值的内容没有改变,它假定没有更深层次的改变,并且它实际上不需要做任何更多的事情(即通知订阅者或重新渲染包装的组件)。 【参考方案2】:

另一种具有独立功能的方法:

export default function reducer(state = initialState, action) 
    switch(action.type) 
        case ADD_TYPE:
             function upsert(array, item) 
    // (1)
    // make a copy of the existing array
    let comments = array.slice();
    const i = comments.findIndex(_item => _item._id === item._id);
    if (i > -1) 
      comments[i] = item;

      return comments;
    
    // (2)
    else 
      // make a copy of the existing array
      let comments = array.slice();
      comments.push(item);

      return comments;
    
  

            return 
     ...state,
    comments: upsert(state.comments, action.payload),
            ;
        default:
            return state;
        

【讨论】:

以上是关于Redux reducer,检查状态数组中是不是存在值并更新状态的主要内容,如果未能解决你的问题,请参考以下文章

Redux 在存储中返回一个空数组 - Reducer 无法正常工作?

React Redux:reducers 是不是应该包含任何逻辑

如何在 React native redux 的 reducer 中向数组添加元素?

Redux:将 Selector 与 Reducers 共存

在 Redux reducer 中对对象数组进行排序

Redux:使用 Redux 更新数组的状态