Redux (W15D1) - Learning Objectives

Redux

  1. Describe the Redux data cycle
  1. Describe the role of the store in the Redux architecture
  1. Explain what a reducer is
// The `state` parameter is assigned a default value of [] in this case.
// We will often assign a default value of [], {}, or some value such as { currentUser: null } that will be modified by actions dispatched to us.
const fruitReducer = (state = [], action) => {
  switch (action.type) {
    case "ADD_FRUIT":
      return [...state, action.fruit];
    default:
      return state;
  }
};

export default fruitReducer;
  1. Use the createStore method to create an instance of a Redux store
import { createStore } from 'redux';

const fruitReducer = (state = [], action) => {
  // TODO implement reducer
}

const store = createStore(fruitReducer);
  1. Use the store.dispatch method to dispatch an action to trigger a state update
// The action that we'll dispatch:
const addOrange = {
  type: 'ADD_FRUIT',
  fruit: 'orange',
};

// The reducer that we'll be impacting
// Notice that this reducer has a case that matches our action's type
// If we didn't have this case, we would hit our default and return the original state
const fruitReducer = (state = [], action) => {
  switch (action.type) {
    case 'ADD_FRUIT':
      return [...state, action.fruit];
    default:
      return state;
  }
};

// Invoking our dispatch function:
console.log(store.getState()); // []
store.dispatch(addOrange);
console.log(store.getState()); // [ 'orange' ]
  1. Use the store.subscribe method to listen for state updates
// Assuming the same reducer and action as the above code block:

// This function is going to be subscribed, meaning it will be invoked after each action is dispatched.
// getState will be the state after the action has already impacted the store
const display = () => {
  console.log(store.getState());
};

// Invoking this function later on will remove the display function from the store's subscriptions, no longer executing the logging functionality
const unsubscribeDisplay = store.subscribe(display);

store.dispatch(addOrange); // [ 'orange', 'orange' ]

// display will no longer be invoked after store.dispatch()
unsubscribeDisplay();

store.dispatch(addOrange); // no output
  1. Use the store.getState method to get the current state
  1. Use a switch statement within a reducer function to handle multiple action types
const fruitReducer = (state = [], action) => {
  switch (action.type) {
    case 'ADD_FRUIT':
      return [...state, action.fruit];
    case 'ADD_FRUITS':
      return [...state, ...action.fruits];
    case 'SELL_FRUIT':
      const index = state.indexOf(action.fruit);
      if (index !== -1) {
        // remove first instance of action.fruit
        return [...state.slice(0, index), ...state.slice(index + 1)];
      }
      return state; // if action.fruit is not in state, return previous state
    case 'SELL_OUT':
      return [];
    default:
      return state;
  }
};
  1. Describe why it’s important for a reducer to avoid mutating the current state when creating the next state
  1. Write an action creator function to facilitate in the creation of action objects
const addFruit = (fruit) => {
  return {
    type: 'ADD_FRUIT',
    fruit,
  };
};
store.dispatch(addFruit("apple"));
store.dispatch(addFruit("banana"));
store.dispatch(addFruit("apple"));
store.dispatch(addFruit("apple"));
store.dispatch(addFruit("orange"));
  1. Use constants to define action types to prevent simple typos in action type string literals
const ADD_FRUIT = 'ADD_FRUIT';
const ADD_FRUITS = 'ADD_FRUITS';
const SELL_FRUIT = 'SELL_FRUIT';
const SELL_OUT = 'SELL_OUT';

const addFruit = (fruit) => ({
  type: ADD_FRUIT,
  fruit,
});

const addFruits = (fruits) => ({
  type: ADD_FRUITS,
  fruits,
});

const sellFruit = (fruit) => ({
  type: SELL_FRUIT,
  fruit,
});

const sellOut = () => ({
  type: SELL_OUT,
});
import { ADD_FRUIT, ADD_FRUITS, SELL_FRUIT, SELL_OUT } from './FruitActions';

const fruitReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_FRUIT:
      return [...state, action.fruit];
    case ADD_FRUITS:
      return [...state, ...action.fruits];
    case SELL_FRUIT:
      const index = state.indexOf(action.fruit);
      if (index !== -1) {
        // remove first instance of action.fruit
        return [...state.slice(0, index), ...state.slice(index + 1)];
      }
      return state; // if action.fruit is not in state, return previous state
    case SELL_OUT:
      return [];
    default:
      return state;
  }
};