【问题标题】:How to write reducers to manipulate this JSON using JavaScript如何使用 JavaScript 编写 reducer 来操作这个 JSON
【发布时间】:2019-12-29 18:25:39
【问题描述】:

我有一个这样的 JSON

"decks": [
    {
      "id": 65,
      "name": "deck1",
      "cards": [
        {
          "question": "q1",
          "answer": "a1"
        },
        {
          "question": "q2",
          "answer": "a2"
        },
        {
          "question": "q3",
          "answer": "a3"
        }
      ]
    },
    {
      "id": 83,
      "name": "deck2",
      "cards": []
    }

现在,我想在添加一张像

这样的卡片后返回卡组对象
   {
      "question": "q4",
      "answer": "a4"
    },

并且该卡应该添加到相应的 id 在这种情况下假设 -65, 并且结果应该像这样返回

"decks": [
    {
      "id": 65,
      "name": "deck1",
      "cards": [
        {
          "question": "q1",
          "answer": "a1"
        },
        {
          "question": "q2",
          "answer": "a2"
        },
        {
          "question": "q3",
          "answer": "a3"
        },
        {
          "question": "q4",
          "answer": "a4"
        }
      ]
    },
    {
      "id": 83,
      "name": "deck2",
      "cards": []
    }

这是我在其中操作对象的减速器代码

case ADD_CARD:

      var index = state.decks.findIndex(x => x.id === action.deckId);


      return {
        ...state.decks,
        decks: state.decks[index].cards.concat(action.newCard),
      };

你能帮我写出正确的reducer代码吗?上面的代码没有给出预期的结果。 感谢您的时间和支持。

【问题讨论】:

    标签: javascript react-native redux react-redux


    【解决方案1】:

    您的state.decks 是数组,因此您不能用您使用过的对象表示法覆盖数组项之一。还有一个小建议:我会说Array.prototype.push() 比Array.prototype.concat() 更适合这个目的。

    假设decks 不代表您的整个状态,并且您尝试在调度操作时更新状态:

    {type:'ADD_CARD', deckId: 65, newCard:{question:'q4',answer:'a4'}}
    

    你对应的 reducer 部分可能看起来像:

    const appReducer = (state, action) => {
        switch(action.type){
            case ADD_CARD: {
                const   {deckId, newCard} = action,
                        {decks} = state,
                        index = decks.findIndex(({id}) => id === deckId)
                decks[index]['cards'].push(newCard)
                return {...state, decks}
            }
            default: return state
        }
    }
    

    您可能会在下面找到作为概念证明的现场演示

    //dependency
    
    const { createStore } = Redux
    
    //default state, reducer, store
    
    const defaultState = {"decks":[{"id":65,"name":"deck1","cards":[{"question":"q1","answer":"a1"},{"question":"q2","answer":"a2"},{"question":"q3","answer":"a3"}]},{"id":83,"name":"deck2","cards":[]}]},
          appReducer = (state=defaultState, action) => {
              switch(action.type){
                  case 'ADD_CARD': {
                      const   {deckId, newCard} = action,
                              {decks} = state,
                              index = decks.findIndex(({id}) => id === deckId)
                      decks[index]['cards'].push(newCard)
                      return {...state, decks}
                  }
                  default: return state
              }
          },
          store = createStore(appReducer)
          
    //dispatchind 'ADD_CARD' action
    
    store.dispatch({type:'ADD_CARD', deckId: 65, newCard:{question:'q4',answer:'a4'}})
    
    //logging the updated store
    
    console.log(store.getState())
    .as-console-wrapper {min-height:100%}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>

    【讨论】:

      【解决方案2】:
      case ADD_CARD:
            const newState = {...state};
            var index = state.decks.findIndex(x => x.id === action.deckId);
            let deck = {...state.decks[index]};
            deck = {...deck, { cards: [...deck.cards, action.newCard] };
            newState[index] = deck;
            return newState;
      

      【讨论】:

        【解决方案3】:

        您可以使用数组映射函数:

        let decks = [
            {
              "id": 65,
              "name": "deck1",
              "cards": [
                {
                  "question": "q1",
                  "answer": "a1"
                },
                {
                  "question": "q2",
                  "answer": "a2"
                },
                {
                  "question": "q3",
                  "answer": "a3"
                }
              ]
            },
            {
              "id": 83,
              "name": "deck2",
              "cards": []
            }]
        
        	const newCard = {
              "question": "q4",
              "answer": "a4"
            }
            
            const newArray = decks.map(x => x.id === 65
        ? {...x, cards: [...x.cards, newCard]}
        : x)
            
            console.log(newArray)

        【讨论】:

        • Array.prototype.map() 方法不必要地遍历整个数组,而 Array.prototype.findIndex() 在匹配时停止循环(在这种特殊情况下是第一项)。因此,从性能的角度来看,后者更为优化。这就是为什么它被 OP 尝试并在my answer 中成功实施的原因。
        猜你喜欢
        • 2019-01-11
        • 1970-01-01
        • 2012-02-03
        • 1970-01-01
        • 2011-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多