首页 > 解决方案 > Trying to delete an element from an array with objects

问题描述

I want to write a reducers-function that deletes an element of an array. The array looks like that:

Array [
  Object {
    "category": "First Course",
    "id": 0,
    "name": "Feta im Backofen gratiniert",
    "price": 9.8,
  },
  Object {
    "category": "First Course",
    "id": 1,
    "name": "Feta gebacken in der Kruste",
    "price": 9.8,
  },
  Object {
    "category": "First Course",
    "id": 2,
    "name": "Frischer Oktapus",
    "price": 9.8,
  }]

Here is my reducer class:

const initialState = {
    restaurantId:0,
    cartItems:[],
    tableNumber:0,
}

const reducers = (state = initialState, action) => {
    switch (action.type) {
        case 'UPDATE_ID':
            return {
                ...state,
                restaurantId: action.payload
            };
        case 'ADD_ITEM_TO_CART':
            return {
                ...state,
                cartItems:[...Object.assign([],{...state.cartItems}),action.payload.item]
            };
        case 'UPDATE_TABLE_NUMBER':
            return{
                tableNumber: action.payload
            };
        case 'REMOVE_ITEM_FROM_CART':
            console.log(action.payload,state.cartItems);
            return{
                ...state,
                cartItems: state.cartItems.splice(action.payload,1)

            }
    }
    return state
}

export default reducers;

When I'm calling the 'REMOVE_ITEM_FROM_CART'-case, there are different events that occure. Sometimes multiple array elements get removed and sometimes the right one gets removed. I don't know what's the problem here. I also console.log the action.payload which gives the index of the array element that I want to remove. It's always the correct payload.

EDIT: This is the component in which the action gets called:

 import React from "react";
    import { StatusBar } from "expo-status-bar";
    import { NavigationActions } from "react-navigation";
    import { ImageBackground, StyleSheet, View, Text, TextInput, TouchableOpacity } from "react-native";
    import ShoppingBag from "../components/ShoppingBag";
    import {connect} from 'react-redux';
    
    class ShoppingBagScreen extends React.Component {
    
        returnOptionsShoppingBag=()=>{
            if(this.props.cartItems.length===0 ||typeof this.props.cartItems.length===undefined) {
                    return(
                        <View>
                            <Text style={{fontSize:20}}>Ihr Warenkorb ist leer</Text>
                        </View>
                    )
                }else{
                return(
                    <View>
                <ShoppingBag shoppingBag={this.props.cartItems} onPress={this.props.deleteCartItem}/>
                <Text/>
                        {this.viewOrderButton()}
                    </View>
    
                )}
        };
    
        viewOrderButton(){
            if(this.props.tableNumber>0){
            return(
            <View>
            <TouchableOpacity >
                <Text style={{fontSize:20, color:'red'}}>Kostenpflichtig bestellen</Text>
            </TouchableOpacity>
            </View>
            )}else{
            return(
                <View>
                    <TouchableOpacity onPress={this.orderAlert}>
                    <Text style={{color:'red',opacity:0.3,fontSize:20}}>Kostenpflichtig bestellen</Text>
                    </TouchableOpacity>
                </View>
                )}
            };
    
        orderAlert(){
            return(
                alert('Bitte wählen Sie eine Tischnummer')
            )
        }
    
        render() {
            return (
                <View style={styles.Background}>
                    <Text style={{fontSize:20}}>Ihre Tischnummer lautet: {this.props.tableNumber}</Text>
                    <Text/>
                    {this.returnOptionsShoppingBag()}
                </View>
            )
        }
    
    
    }
    
    
    function mapDispatchToProps(dispatch){
    
        return {
            deleteCartItem: (index) => dispatch({type: 'REMOVE_ITEM_FROM_CART', payload: index})
        }}
    
    function mapStateToProps(state){
        return{
            cartItems: state.cartItems,
            tableNumber: state.tableNumber
            }
        }
    
    
    export default connect(mapStateToProps,mapDispatchToProps)(ShoppingBagScreen);
 

This is the ShoppingBag-component:

import React from 'react';
import {View,Text,TouchableOpacity} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';

export default class ShoppingBag extends React.Component{

    renderShoppingBag = (shoppingBag)=>{
        return shoppingBag.map((item,index)=>{
            return(
                <View key={index} style={{flexDirection:'row'}}>
                    <Text style={{fontSize:20}}> {item.name} {item.price}0€     </Text>
                    <TouchableOpacity onPress={()=>this.props.onPress(index)}>
                    <Icon name='trash' size={20}/>
                    </TouchableOpacity>
                </View>
            )
        })
    }

    render() {
        return(
            <View>
            {this.renderShoppingBag(this.props.shoppingBag)}
            </View>
        )
    }
}

Thanks in advance!

标签: javascriptreact-nativereduxreact-redux

解决方案


首先,我建议将您的数组操作从 return 语句中提取出来。

事实上,我强烈建议在每种情况下将状态对象和数组的副本设置为您的首要任务。

case 'REMOVE_ITEM_FROM_CART':
  let cartAfterRemove = [...state.cartItems];
  cartAfterRemove.splice(action.payload, 1);
  //to confirm successful splice;
  console.log(cartAfterRemove);
  let newState = {...state, cartItems: cartAfterRemove};
  return newState;
}

如果你对嵌套项目不小心并且有 0 突变,redux 会变得非常时髦。您也可以发送对象的 id 而不是索引,但这需要更多的重构。

https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns <- 有一些很好的例子。


推荐阅读