Never Mutate State

Never Mutate State
0

#1

Tell us what’s happening:
The Redux store should exist and initialize with a state equal to the todos array in the code editor.
Cannot read property ‘map’ of undefined

Your code so far


const ADD_TO_DO = 'ADD_TO_DO';

// A list of strings representing tasks to do:
const todos = [
  'Go to the store',
  'Clean the house',
  'Cook dinner',
  'Learn to code',
];

const defaultState = {
  todos: todos
};


const immutableReducer = (state = defaultState, action) => {
  switch(action.type) {
    case ADD_TO_DO:
      // don't mutate state here or the tests will fail
      let arr = state.todos.map(x => x);
      return (arr.push(action.todo));
    default:
      return state;
  }
};

// an example todo argument would be 'Learn React',
const addToDo = (todo) => {
  return {
    type: ADD_TO_DO,
    todo: todo
  }
}

const store = Redux.createStore(immutableReducer);
store.dispatch(addToDo("Learn React!"));

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/front-end-libraries/redux/never-mutate-state


#2

Hi @pankajthukran32, be careful, the push method returns the new length of the array, not the array itself.

This should work :

      let arr = state.map(x => x);
      arr.push(action.todo);
      return arr;

Also, as a bonus, you could have used another method that is concat just like that :

return state.concat(action.todo)

:slightly_smiling_face:


#3

Thomlom is right about that, but there are some other problems. But with the shape of your state, it should be something like:

      let arr = state.todos.map(x => x);
      arr.push(action.todo);
      return ({ todos: arr });

But that’s part of the problem - you’ve changed the shape of the state and it will confuse the test. Why did you create:

const defaultState = {
  todos: todos
};

They want that array directly in state, not as an array wrapped in and object, that’s why the original problem gave you this:

//...
const todos = [
  'Go to the store',
  'Clean the house',
  'Cook dinner',
  'Learn to code',
];

const immutableReducer = (state = todos, action) => {
//...

So, if you fix that, you get what thomlom was suggesting. But why use map? The traditional way to copy and array is slice.

let arr = state.slice();

This probably does the same thing as the map but might be a bit faster and is what people expect to see.

thomlom’s suggestion of concat almost works, but it expects an array as the parameter so it would have to be:

return state.concat([ action.todo ])

But why not do it the ES6 way?

let arr = [ ...state, action.todo]

Actually, at that point you don’t need to use the variable arr but can just return [ ...state, action.todo] without the middle-man variable.

This is much cleaner and is the more “modern” way of doing it. Redux especially really embraces ES6.


#4

return state.concat(action.todo)

This works perfectly fine for me. :slightly_smiling_face:


#5

My brain hurts trying to understand this stuff.


#6

Actually, Tom’s suggest of using concat works as is. The argument passed to concat does not need to be an array.

const todos = [
  'Learn to code',
  'Get a job'
];

const todo = 'Make money'

const final = todos.concat(todo)
console.log(final); // displays ['Learn to code', 'Get a job', 'Make money']