简体   繁体   English

将 Object 添加到 Redux React 中的嵌套数组

[英]Adding an Object to a Nested Array in Redux React

I'm trying to add a new card in the banking_cards array inside of the paymentMethods array.我正在尝试在banking_cards arraypaymentMethods数组中添加一张新卡。 The banking_cards array is inside the paymentMethods array. banking_cards数组位于paymentMethods数组中。 So i wanted to insert the new card object inside the banking_cards array.所以我想在banking_cards数组中插入新卡object。 My code below produces an error which says state.paymentMethods.banking_cards is not iterable .我下面的代码产生一个错误,上面写着state.paymentMethods.banking_cards is not iterable

TAKE NOTE记笔记

banking_cards array is inside the paymentMethods array banking_cards数组在paymentMethods数组中

export const initialState = {
    paymentMethods: [],
  };



  case paymentMethodConstants.ADD_CARD_SUCCESS:
    return {
      ...state,
      paymentMethods: [
        ...state.paymentMethods,
        banking_cards: [...state.paymentMethods.banking_cards, action.payload],
      ],
    };

JSON JSON

paymentMethods = [
  {
    "id": 8,
    "customer_token": "epofjoe",
    "banking_cards": [
      {
        "id": 1,
        "banking_token": "AAA",
        "last_4": "0006",
        "exp_year": 2021,
        "exp_month": 12,
        "cvc": 876
      },
      {
        "id": 2,
        "banking_token": "BBB",
        "last_4": "0002",
        "exp_year": 2022,
        "exp_month": 12,
        "cvc": 877
      },
    ]
  }
]

When adding a card to a payment method your action needs to contain what payment method the card needs to be added to.将卡添加到付款方式时,您的操作需要包含该卡需要添加到的付款方式。

Below is a working example of how you could do that:下面是一个工作示例,说明如何做到这一点:

 const { Provider, useDispatch, useSelector } = ReactRedux; const { createStore, applyMiddleware, compose } = Redux; const createId = ((id) => () => id++)(3); const initialState = { paymentMethods: [ { id: 8, banking_cards: [ { id: 1, }, { id: 2, }, ], }, { id: 9, banking_cards: [ { id: 1, }, { id: 2, }, ], }, ], }; //action types const ADD_CARD_SUCCESS = 'ADD_CARD_SUCCESS'; //action creators const addCardSuccess = (payementMethodId, card) => ({ type: ADD_CARD_SUCCESS, payload: { payementMethodId, card }, }); const reducer = (state, { type, payload }) => { if (type === ADD_CARD_SUCCESS) { const { payementMethodId, card } = payload; return {...state, paymentMethods: state.paymentMethods.map((method) => method.id === payementMethodId? {...method, banking_cards: [...method.banking_cards, card, ], }: method ), }; } return state; }; //selectors const selectPaymentMethods = (state) => state.paymentMethods; //creating store with redux dev tools const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( reducer, initialState, composeEnhancers( applyMiddleware(() => (next) => (action) => next(action) ) ) ); //pure component so not re rendering when nothing changed const Card = React.memo(function Card({ card }) { return <li>card: {card.id}</li>; }); //pure component so it won't re render when nothing changes const PaymentMethod = React.memo(function PaymentMethod({ paymentMethod, }) { const dispatch = useDispatch(); return ( <li> payment method id: {paymentMethod.id} <ul> {paymentMethod.banking_cards.map((card) => ( <Card key={card.id} card={card} /> ))} </ul> <button onClick={() => dispatch( //dispatch action with payment method id addCardSuccess(paymentMethod.id, { //the new card to be added id: createId(), }) ) } > Add card </button> </li> ); }); const App = () => { const paymentMethods = useSelector(selectPaymentMethods); return ( <ul> {paymentMethods.map((paymentMethod) => ( <PaymentMethod key={paymentMethod.id} paymentMethod={paymentMethod} /> ))} </ul> ); }; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script> <div id="root"></div>

With immer I'd use payment method index and not need the map:使用 immer 我会使用付款方式索引,而不需要 map:

 const { Provider, useDispatch, useSelector } = ReactRedux; const { createStore, applyMiddleware, compose } = Redux; const { produce } = immer; const createId = ((id) => () => id++)(3); const initialState = { paymentMethods: [ { id: 8, banking_cards: [ { id: 1, }, { id: 2, }, ], }, { id: 9, banking_cards: [ { id: 1, }, { id: 2, }, ], }, ], }; //action types const ADD_CARD_SUCCESS = 'ADD_CARD_SUCCESS'; //action creators const addCardSuccess = (index, card) => ({ type: ADD_CARD_SUCCESS, payload: { index, card }, }); const reducer = (state, { type, payload }) => { if (type === ADD_CARD_SUCCESS) { //lot less hassle using index and immer const { index, card } = payload; return produce(state, (draft) => { draft.paymentMethods[index].banking_cards.push(card); }); } return state; }; //selectors const selectPaymentMethods = (state) => state.paymentMethods; //creating store with redux dev tools const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( reducer, initialState, composeEnhancers( applyMiddleware(() => (next) => (action) => next(action) ) ) ); //pure component so not re rendering when nothing changed const Card = React.memo(function Card({ card }) { return <li>card: {card.id}</li>; }); //pure component so it won't re render when nothing changes const PaymentMethod = React.memo(function PaymentMethod({ paymentMethod, index, }) { const dispatch = useDispatch(); return ( <li> payment method id: {paymentMethod.id} <ul> {paymentMethod.banking_cards.map((card) => ( <Card key={card.id} card={card} /> ))} </ul> <button onClick={() => dispatch( //dispatch action with payment method index addCardSuccess(index, { //the new card to be added id: createId(), }) ) } > Add card </button> </li> ); }); const App = () => { const paymentMethods = useSelector(selectPaymentMethods); return ( <ul> {paymentMethods.map((paymentMethod, index) => ( <PaymentMethod key={paymentMethod.id} paymentMethod={paymentMethod} index={index} /> ))} </ul> ); }; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script> <script src="https://unpkg.com/immer@7.0.5/dist/immer.umd.production.min.js"></script> <div id="root"></div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM