user6002037
user6002037

Reputation:

React redux - issues adding multiple items to an array in state tree object

I am looking at redux and adding names to an array. The code below works (kind of!).

I have a few issues.

  1. I know that it is advised to create a new state tree object each time the state is passed through the reducer, however I thought it should still work even if I change the state object passed in. In my code below the console.log(store.getState()); works if I use var newArr = state.names.concat(action.name); but not if I use state.names.push(action.name);

  2. If I add another store.dispatch(action) the code doesn't work.

    store.dispatch({type: 'ADD_NAME',name: 'PhantomTwo'});

Can anyone explain why this is so?

  1. Finally, do I need to return state again outside the switch statement?

Here is the code I currently have below.

const initialState = {
    names: []
}

function namesApp(state = initialState, action) {
    switch(action.type) {
        case 'ADD_NAME':
            var newArr = state.names.concat(action.name);
            return newArr;
        default: 
            return state;
    }
}

let store = createStore(namesApp);

store.dispatch({
    type: 'ADD_NAME',
    name: 'Phantom'
});

console.log(store.getState()); //returns `["Phantom"]`

Upvotes: 2

Views: 3114

Answers (2)

Jyothi Babu Araja
Jyothi Babu Araja

Reputation: 10282

This is the behavior of array object mutability

Since React highly cares about state change for re-rendering, so we need to take care of mutability.

The below snippet explains the array mutability.

let x = [];

let y = x;

console.log(x);
console.log(y);

y.push("First");

console.log(x);
console.log(y);

let z = [...x]; //creating new reference

console.log(z);

x.push("Second");

console.log(x); //updated
console.log(y); //updated
console.log(z); //not updated

So for better functionality your reducer will be like

function namesApp(state = initialState, action) {
    switch(action.type) {
        case 'ADD_NAME':
            return {
                ...state, //optional, necessary if state have other data than names
                ...{
                   names: [...state.names, action.name]
                }
            };
        default: 
            return state;
    }
}

Upvotes: 5

FlatLander
FlatLander

Reputation: 1757

[].concat returns a new array. But your state was { name: [] }. Inspite of returning newly build object with new names, the code above returned the new names array.

Vanilla solution

const initialState = { names: [] };

function namesApp(state = initialState, action) {
    switch(action.type) {
        case 'ADD_NAME':
            var newArr = state.names.concat(action.name);

            return {
                ...state,
                names: newArr
            };
        default: 
            return state;
    }
}

immutability-helper

For this type of work I would use immutability-helper

import u from 'immutability-helper'; 

function namesApp(state = initialState, action) {
    switch(action.type) {
        case 'ADD_NAME':    
            return u(state, {
                names: {
                    $push: action.name
                }
            });
        default: 
            return state;
    }
}

learn how to use immutability-helper https://facebook.github.io/react/docs/update.html

Upvotes: 2

Related Questions