0
votes

I am just playing around with Redux, so sorry for any mistakes or bad practices.

I basically have a list of computer parts which the user can select/deselect. Each part is a JS object which has id, name, price and selected field:

const initialState = {
    products: [
        {product_id: 0, product_name: "Hard Drive 320 GB 5400 RPM", price: 1450, selected: false},
        {product_id: 1, product_name: "Solid State Drive 128 GB R/W - 420 MB/s", price: 1880, selected: false},
        {product_id: 2, product_name: "Gigabyte MB A270S AM4 DDR4 3200HZ OC HDMI/VGA/DVI", price: 3560, selected: false},
        {product_id: 3, product_name: "Asus MB A420M LGA 1151 3200HZ OC HDMI/VGA", price: 3660, selected: false},
        {product_id: 4, product_name: "nVidia GTX 1050 Ti 4GB GDDR5 VRAM", price: 13450, selected: false},
        {product_id: 5, product_name: "Intel i5 7200 kabylake CPU 3.6 GHz 4 cores 4 threads", price: 9800, selected: false},
        {product_id: 6, product_name: "AMD Ryzed 5 2600G CPU 3.2 GHz 4 cores 4 threads", price: 9380, selected: false},
        {product_id: 7, product_name: "8 GB Hyper-X DDR4 RAM memory 3200 MHz CL15", price: 3450, selected: false},
        {product_id: 8, product_name: "450W Sharkoon PSU 80 plus black semi modular", price: 2250, selected: false},
        {product_id: 9, product_name: "ATX Case w/ Acrilyc Glass panel & LED Strips", price: 1720, selected: false},
    ],
    sum: 0
}

(this is just a practice so im not loading the data from a rest api or whatever)

Then, i subscribe to the redux store with my App component using the connect function, and i pass in my mapStateToProps and mapDispatchToProps functions:

function mapStateToProps(state){
    return {
        products: state.products,
        sum: state.sum
    }
}

function mapDispatchToProps(dispatch){
    return {
        toggle: (product_id) => dispatch(ACTIONS.toggle(product_id))
    }
}


export default connect(mapStateToProps, mapDispatchToProps)(App)

Then inside of my app component, I create a const array to which i map all the products and generate a JSX return of a div with content inside it, and on each div i add an event linstener (onClick) which triggers the this.props.toggle dispatch:

const products = this.props.products.map(product => {
    return (
        <div className="product" key={product.product_id} onClick={ () => {this.props.toggle(product.product_id) }}>
            <h2>{product.product_name}</h2>
            {product.selected ? ('') : (<h3>{product.price}</h3>)}
        </div>
    )
})

And when the action is dispatched, this is what happens in the reducer:

switch(action.type){
    case ACTION_TYPES.PRODUCT_TOGGLE:
        const newState = state
        newState.products[action.payload].selected = !newState.products[action.payload].selected
        if(newState.products[action.payload].selected === true){
            newState.sum = newState.sum + newState.products[action.payload].price
        } else {
            newState.sum = newState.sum - newState.products[action.payload].price
        }
        console.log(newState.sum)
        return newState
    default:
        return state
}

If i do a console log in the reducer, i do see the change happening, but the props of the container component do not update.

2
Is the const products = this...... code in your render method or executed when render is called ?Titus
It runs every time the render method is called (or whenever the component updates)SuperSimplePimpleDimple

2 Answers

2
votes

You are mutating the state object, newState and state are the same object reference that's why the UI is not updating.

You have to return a new object from the reducer.

Create a new object before mutating the object like this

const newState = { ...state }
1
votes

When you run newState = state you are just making a variable that's a reference to the same object as your old state, so as you assign new values to the object, you are mutating the old object.

Redux and React-Redux use strict equality checks to determine if your state has been updated. Since the object references are the same, it thinks that the state has not changed.

const oldState = { a: 1 };
const newState = oldState;
newState.a = 2;
console.log(oldState);
console.log(newState);
console.log(oldState === newState);

See this article on the subject of immutability: https://redux.js.org/faq/immutable-data#why-is-immutability-required-by-redux