Reputation: 133
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!
Upvotes: 0
Views: 74
Reputation: 71
First, I'd suggest pulling your array action out of the return statement.
In fact, I highly recommend setting copies of your state objects and arrays as your first priority in each case.
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;
}
redux can get really funky if you're not careful with nested items and having 0 mutation. You could also send the id of the object rather than the index, but that would entail more refactoring.
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns <- has some great examples.
Upvotes: 1
Reputation: 6967
Payload should be an index of the item because splice works on index not number of items to be deleted
Upvotes: 0