0

I am working on a shopping basket component in React Native. The content and price of the basket get saved in the global redux store. When the user selects an item, an action gets dispatched to add the item to the basket and to update the total basket price.

The UI however does not get updated on this global state change.

My Reducer

const INITIAL_STATE = {
basket: [],
basketPrice: 0,
};

const mainReducer = (state = INITIAL_STATE, action) => {
    const stateCpy = state;
    switch (action.type) {
        case 'SET_BASKET':
            stateCpy.basket = action.payload
            return stateCpy;
        case 'ADD_TO_BASKET':
            stateCpy.basket.push(action.payload)
            return stateCpy
        case 'REMOVE_FROM_BASKET':
            let tempItems = stateCpy.basket
            for (var x = 0; x < stateCpy.basket.length; x++) {
                if (stateCpy.basket[x]._id === action.payload) {
                    tempItems.splice(x, 1)
                    break;
                }
            }
            stateCpy.basket = tempItems
            return stateCpy
        case 'SET_BASKET_PRICE':
            stateCpy.basketPrice = action.payload
            console.log(stateCpy.basketPrice)
            return stateCpy
        default:
            return state
    }
};

export default mainReducer

My Actions

const setBasket = basket => ({
    type: 'SET_BASKET',
    payload: basket,
});
const addToBasket = item => ({
    type: 'ADD_TO_BASKET',
    payload: item,
});
const removeFromBasket = item_id => ({
    type: 'REMOVE_FROM_BASKET',
    payload: item_id,
});

const setBasketPrice = price => ({
    type: 'SET_BASKET_PRICE',
    payload: price,
});

export default actions = {
    setBasket,
    addToBasket,
    removeFromBasket,
    setBasketPrice
}

My UI Component

... 

import { useSelector, useDispatch } from 'react-redux'

export const RestaurantView = ({ navigation, route }) => {
    const basket = useSelector((state) => state.basket)
    const basketPrice = useSelector((state) => state.basketPrice)
    
    const dispatch = useDispatch()

...

function calcBasketPrice(){
        let tempBasketPrice = 0
        basket.forEach(element => {
            tempBasketPrice += element.price
        });
        return tempBasketPrice
        
    }

    function addToBasket(item) {
        dispatch(actions.setBasketPrice(calcBasketPrice() + item.price))
        dispatch(actions.addToBasket(item))
    }


return ( <View>
    <ItemCard onPress={addToBasket}> </ItemCard>
    <Text style={{ textAlign: "right", padding: 15, fontSize: 20 }}> {basketPrice}</Text>
</View>)

}

When logging the basketPrice to console in the reducer, it logs the correct, updated value on each press/dispatch but there no changes in the UI. When a local state change is made to force a rerender, it renders with the correct value from the global store.

1 Answer 1

1

Your stateCpy variable is actually not a copy, but just a reference to state - so your reducer is actually modifying the old redux state instead of creating a new one.

Since this is a very outdated style of Redux and in modern Redux createSlice reducers it is totally okay to modify state, I would recommend you not to fix this in legacy Redux, but to take a look at modern Redux - which is also less error-prone and about 1/4 of the code you would write with legacy Redux. Rewriting your reducer is not a lot of work and in the long run you will really benefit from the (since 2019) new style.

Take a look at the official Redux tutorial

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.