Redux: Never Mutate State

  • Today FreeCodeCamp will be giving us a lesson about enforcing the key [principle of state immutability in Redux. Which means that you never modify state directly. Instead you return a new copy of state.
  • Redux does not actively enforce state immutability in its store or reducers. Remember strings and numbers are primitive values and are immutable by nature. In other words, 3 is always 3. You cannot change the value of the number 3. An array or object, however, is mutable.
  • Code:
  • 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 immutableReducer = (state = todos, action) => {
      switch(action.type) {
        case ADD_TO_DO:
          // Don't mutate state here or the tests will fail
          return
        default:
          return state;
      }
    };
    
    const addToDo = (todo) => {
      return {
        type: ADD_TO_DO,
        todo
      }
    }
    
    const store = Redux.createStore(immutableReducer);
  • Above we have a store and reducer in the code editor for managing to-do items. You have to finish writing the ADD_TO_DO case in the reducer to append a new-to-do to the state. You have tp find a way to return a new array with the item from action.todo appended to the end.

  • Answer:

  • const ADD_TO_DO = 'ADD_TO_DO';
    
    const todos = [
      'Go to the store',
      'Clean the house',
      'Cook dinner',
      'Learn to code',
    ];
    
    const immutableReducer = (state = todos, action) => {
      switch(action.type) {
        case ADD_TO_DO:
          let newList = [...todos]
          newList.push(action.todo)
          return newList;
        default:
          return state;
      }
    };
    
    const addToDo = (todo) => {
      return {
        type: ADD_TO_DO,
        todo
      }
    }
    
    const store = Redux.createStore(immutableReducer);
    
    store.dispatch(addToDo('PS5 Time'))****
    console.log(store.getState()) // 
    [ 'Go to the store',
      'Clean the house',
      'Cook dinner',
      'Learn to code',
      'PS5 Time' ]
    
    
    console.log(todos) // 
    [ 'Go to the store',
      'Clean the house',
      'Cook dinner',
      'Learn to code' ]
    Use the Spread Operator on Arrays
  • (ES6) To help enforce state immutability in Redux is the spread operator: .... which I used in the lesson above which produces a new array from an existing array.
  • To clone an array but add additional values in the new array, you could write [...myArray, 'new value']. This would return a new array composed of the values in myArray and the string new value as the last value.
  • It's important to know that it only makes a shallow copy of the array. It only provides immutable array operations for one-dimensional arrays.

  • Code:

  • const immutableReducer = (state = ['Do not mutate state!'], action) => {
      switch(action.type) {
        case 'ADD_TO_DO':
          // Don't mutate state here or the tests will fail
          return
        default:
          return state;
      }
    };
    
    const addToDo = (todo) => {
      return {
        type: 'ADD_TO_DO',
        todo
      }
    }
    
    const store = Redux.createStore(immutableReducer);
  • Answer:
  • const immutableReducer = (state = ['Do not mutate state!'], action) => {
      switch(action.type) {
        case 'ADD_TO_DO':
          let newArray = [...state, action.todo]
          return newArray
        default:
          return state;
      }
    };
    Remove an Item from an Array
  • Now we gotta practice removing items from an array. Other useful JavaScript methods include slice() and concat().

  • The reducer and action creator were modified to remove an item from an array based on the index of the item. Let's Finish writing the reducer so a new state array is returned with the item at the specific index removed.

  • *Code:
    const immutableReducer = (state = [0,1,2,3,4,5], action) => {
      switch(action.type) {
        case 'REMOVE_ITEM':
          // Don't mutate state here or the tests will fail
          return
        default:
          return state;
      }
    };
    
    const removeItem = (index) => {
      return {
        type: 'REMOVE_ITEM',
        index
      }
    }
    
    const store = Redux.createStore(immutableReducer);
  • Answer:
  • const immutableReducer = (state = [0,1,2,3,4,5], action) => {
      switch(action.type) {
        case 'REMOVE_ITEM':
          let a = state.slice(0, action.index)
          let b = state.slice(action.index + 1)
          return a.concat(b)
        default:
          return state;
      }
    };
    
    const removeItem = (index) => {
      return {
        type: 'REMOVE_ITEM',
        index
      }
    }
    
    const store = Redux.createStore(immutableReducer);
    Larson, Q., 2019. Frontend Development Libraries. [online] Freecodecamp.org. Available at: https://www.freecodecamp.org/learn/front-end-development-libraries/redux

    36

    This website collects cookies to deliver better user experience

    Redux: Never Mutate State