useReducer

Vad är useReducer?

  • En hook som används för att hantera tillstånd i React
  • Används ofta istället för useState, speciellt för komplexa tillstånd
  • Har sin bakgrund i klassisk Redux som den såg ut innan `Redux Toolkit``

Byggstenar

  • En reducer-funktion
  • En dispatch-funktion
  • En action
  • Ett state

State

  • Ett state är ett objekt som innehåller all data som behövs för att rendera en komponent
  • Ett state kan innehålla allt från en enkel boolean till ett komplext objekt

Exempel, todo-state:

{
  "isLoading": false,
  "todos": [
    {
      "id": 1,
      "text": "Learn React",
      "completed": false
    },
    {
      "id": 2,
      "text": "Learn Redux",
      "completed": false
    }
  ]
}

Dispatch

  • Varje gång statet ska uppdateras måste en dispatch-funktion anropas
  • Man skickar in en action som argument till dispatch-funktionen

Exempel:

dispatch({ type: 'ADD_TODO', payload: { id: 3, text: 'Learn TypeScript', completed: false } });

Action

  • Type: En sträng som beskriver vilken typ av action som ska utföras
  • Payload: Data som behövs för att utföra actionen
{
  "type": "ADD_TODO",
  "payload": {
    "id": 3,
    "text": "Learn TypeScript",
    "completed": false
  }
}

Action creator

  • En funktion som returnerar en action
  • Används för att slippa skriva action-objektet manuellt
const addTodo = (text: string) => {
  return {
    type: 'ADD_TODO',
    payload: {
      id: Math.random(),
      text,
      completed: false,
    },
  };
};

Reducer

  • När man har dispatchat en action så kommer reducer-funktionen att anropas
  • Reducer-funktionen tar emot ett state och en action som argument
  • Den innehåller typiskt sett en switch-sats som baserat på actionens typ returnerar ett nytt state

Exempel reducer

const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        ...state,
        todos: [...state.todos, action.payload],
      };
    default:
      return state;
  }
};

Initial state

  • Initial state är det state som används när komponenten renderas för första gången
const initialState = {
  todos: [
    {
      id: 1,
      text: 'Learn React',
      completed: false,
    },
    {
      id: 2,
      text: 'Learn Redux',
      completed: false,
    },
  ],
};

Sätta upp useReducer

const [state, dispatch] = useReducer(reducer, initialState);

Med typescript

type State = {
  todos: Todo[];
};

type Action = { type: 'ADD_TODO'; payload: Todo }
    | { type: 'TOGGLE_TODO'; payload: number };

const reducer = (state: State, action: Action) => {

};

const [state, dispatch] = useReducer(reducer, initialState);

Immutable state

  • State ska inte muteras, utan en ny kopia ska returneras
  • Detta för att React ska kunna avgöra om statet har ändrats eller inte

Pure reducer

  • En reducer-funktion ska vara en pure function
  • Den ska inte ha några sideffekter
//Exempel, not pure:
const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case 'ADD_TODO':
      state.todos.push(action.payload);
      return state;
    default:
      return state;
  }
};

Demo - refaktorisera todo-app