アレイのbanking_cards array
内側に新しいカードを追加しようとしていpaymentMethods
ます。banking_cards
配列は内部にあるpaymentMethods
配列。そこで、新しいカードオブジェクトをbanking_cards
配列内に挿入したかったのです。以下の私のコードは、というエラーを生成しますstate.paymentMethods.banking_cards is not iterable
。
メモを取る
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
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
},
]
}
]
カードを支払い方法に追加する場合、アクションには、カードを追加する必要のある支払い方法を含める必要があります。
以下は、それを行う方法の実用的な例です。
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>
イマーでは、支払い方法のインデックスを使用し、マップは必要ありません。
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/[email protected]/dist/immer.umd.production.min.js"></script>
<div id="root"></div>
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加