【问题标题】:How do I add an element to array in reducer in Redux when the array does not yet exist?当数组尚不存在时,如何在 Redux 的 reducer 中向数组添加元素?
【发布时间】:2020-04-18 21:21:31
【问题描述】:

我有一个代码沙箱来演示我在使用 Redux 和 React 时遇到的问题。

https://codesandbox.io/s/reactredux-3edy8

基本上这个reducer不起作用:

const initialState = {
  byId: {}
};

function addReducer(state = initialState, action) {
  switch (action.type) {
    case "RECEIVE_DATA":
      return {
        ...state,
        byId: {
          ...state.byId,
          [action.payload.id]: [
            ...state.byId[action.payload.id],
            action.payload.data
          ]
        }
      };
    default:
      return state;
  }
}

export default addReducer;

这里是动作:

import { RECEIVE_DATA } from "./actionTypes";

export function action() {
  return {
    type: RECEIVE_DATA,
    payload: {
      id: Math.floor(Math.random() * 2),
      data: Math.floor(Math.random() * 10000)
    }
  };
}

在我自己的应用程序中,它会抛出一个错误,例如 state.byId[action.payload.id] is not iterable,这是真的。但是如何将值推送到尚不存在的数组,因为我不知道 id

我认为可以通过更改 initialState 来解决该问题,或者可能有一个我不知道的函数允许我为其创建 arraypush

【问题讨论】:

  • 因此,例如,如果您的操作的 payload.id 为 1,而您的 payload.data 为 1000,您希望 state.byId.1 包含什么值?
  • state.byId["1"] 将是 ["1000"] 如果 { id: 1, data: 2000 } 发生另一个动作,那么状态将是:{ byId: { "1": ["1000", "2000"] } } 但是,我找到了我相信的答案......现在将其输入.

标签: javascript arrays reactjs redux


【解决方案1】:

我不确定,但我认为你需要这样的东西

 function addReducer(state = initialState, action) {
      switch (action.type) {
        case "RECEIVE_DATA":
          return {
            ...state,
            byId: {
              ...state.byId,
              [action.payload.id]: 
                [action.payload.data]

            }
          };
        default:
          return state;
      }
    }

【讨论】:

  • 这将覆盖已经存在的任何数据。这个想法是将任何新数据附加到现有数组(如果存在)
【解决方案2】:

这个问题的答案在于扁平化状态。我确信还有其他方法可以解决此问题,但我发现这是最干净的。

通常情况下,byId 状态的属性是根据the docs 中的指南通过扁平状态创建的

我更进一步,使byId 属性成为一个数组而不是一个对象。我将id 移动到数组的对象中,就像在这个新沙箱中一样:https://codesandbox.io/s/reactredux-zj1n4

当我将状态映射到我的组件时,我只需要记住 byId 现在是一个数组。

没有功能丢失,如果需要,我的 byId 字段现在可以支持多个不同的 ID(例如,如果我在对象上有多对多关系)

代码如下:

在减速器中

case "RECEIVE_DATA":
      return {
        ...state,
        byId: [...state.byId, action.payload.data]
      };

新动作:

export function action() {
  return {
    type: RECEIVE_DATA,
    payload: {
      data: {
        id: Math.floor(Math.random() * 2),
        value: Math.floor(Math.random() * 10000)
      }
    }
  };
}

【讨论】:

    【解决方案3】:

    先检查数组是否存在。如果是,请添加一个新元素。如果没有,则创建一个包含一个元素的新数组(来自操作的新数据)

    const initialState = {
      byId: {}
    };
    
    function addReducer(state = initialState, action) {
      switch (action.type) {
        case "RECEIVE_DATA":
          return {
            ...state,
            byId: {
              ...state.byId,
              [action.payload.id]: (
                  state.byId[action.payload.id] ? [
                  ...state.byId[action.payload.id],
                  action.payload.data
                ] : [action.payload.data])
            }
          };
        default:
          return state;
      }
    }
    
    export default addReducer;
    

    您可以在此处阅读有关三元语句的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator

    【讨论】:

    • 谢谢你,这是我最终选择的非常好的选择。但是,如果您要投反对票,则应就原因发表评论。我相信我的回答是一个不错的选择,但如果有原因,我想知道它为什么不好。
    • 它没有按照问题所说的那样做
    猜你喜欢
    • 2017-04-16
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    • 1970-01-01
    相关资源
    最近更新 更多