Hopp til hovedinnhold

Tips og triks / 5 minutter /

Hvordan gjøre state-management til en lek

State-management er noe som har skapt både glede og kanskje mest frustrasjon for utviklere. Heldigvis ble frustrasjonen hørt og nye tools som Redux kom på banen og løste alle problemene 🥳 Eller? Tja, Redux kan oppleves som tungt, stort og litt uoverkommelig 🙃 Men fortvil ikke, for i dette innlegget vil jeg introdusere Redux Toolkit, som gjør Redux-bruk litt mindre kjipt og litt mer overkommelig.

Mann på sklie

Hva er Redux?

Redux er et Javascript-bibliotek som kan brukes til å administrere staten til en applikasjon som fungerer med de fleste Javascript-rammeverk, slik som React, Angular og Vue.

En applikasjon har ofte flere komponenter, der hver av de styrer sin egen state. Men når applikasjonen blir stor og har mange komponenter som samhandler med hverandre, kan det bli utrolig vanskelig å holde styr på endringer og oppdateringer av states. Redux tar hånd om dette ved å ha kun én state for hele applikasjonen der hver komponent har tilgang til denne staten. Generelt har Redux fire deler som danner en full sirkel:

Redux-sirkel
Redux-sirkel
  • View: Dette er selve UI’et og det en bruker ser. Dette er starten av en Redux-“reise”. Som et eksempel kan vi bruke en counter-applikasjon:
Counter-applikasjon eksempel
Counter-applikasjon eksempel
  • Action: Noe som skjer, enten automatisk, eller ved at en bruker gjør noe i View. En Action har alltid en type, og eventuelt en payload. Typen beskriver hvilken type Action som skjer, og en payload har med seg eventuell data som trengs for å utføre denne Action. Å sende en Action utføres gjennom en dispatch.

    I counter-eksempelet vårt kan en Action være å trykke på (+) eller (-) eller å skrive inn et tall og trykke “add”. Dette hadde sendt ut en Action slik:
1store.dispatch({ type:ADD'})
2//eller
3store.dispatch({ type: 'ADD_CUSTOM', numberToAdd: 5 })
  • Reducer: En Reducer tar imot en Action og håndterer den. Man kan enten ha en Reducer for hele applikasjonen, eller hvis det er en større app, dele den inn i flere Reducers, som kategorier. En Reducer håndterer den nåværende staten og har flere cases for de ulike type Actions som blir sendt inn, oftest i form av en switch-statement. Reducer’en matcher Action-typen opp mot sine cases og om de matcher utfører den handlingen.

    I counter-eksempelet ville en Reducer sett slik ut:
1function counterReducer(state = { value: 0 }, action) {
2    switch (action.type) {
3        case 'ADD':
4            return { value: state.value + 1 };
5        case 'ADD_CUSTOM':
6            return { value: state.value + action.numberToAdd };
7        case 'SUBTRACT':
8            return { value: state.value - 1 };
9        default:
10            return state;
11    }
12}
  • Store: En Store holder på alle states som er i applikasjonen. Det er her den oppdaterte staten sendes til etter at en Action har blitt håndtert i en Reducer. I counter-eksempelet kan en Store bli lagd slik:
1const store = createStore(counterReducer);

Redux er altså et imponerende verktøy som lett kan utvides og opprettholdes. Samtidig kommer det med noen ulemper. Blant annet at det kan bli et rotete system som er vanskelig å finne frem i og forstå, og det kan bli en del boilerplate-kode. Spesielt er det vanskelig å ha kontroll på Actions og Reducere i større applikasjoner. Av den grunn kom teamet bak Redux ut med noe som skulle gjøre denne prosessen lettere: Redux Toolkit.

Hvordan brukes Redux Toolkit?

Redux Toolkit er en npm-pakke som installeres i tillegg til redux. Hovedforskjellen fra vanlig Redux og Redux Toolkit er at i vanlig Redux skrives alle Actions og Reducers separat, noe som kan føre til forvirring med hvilke Actions som hører til hvilke Reducers og en rekke andre ting. Med Redux Toolkit derimot blir Actions, Reducers og State kombinert i kategorier, kalt Slices. I Slices lagres både State, Actions og Reducers.

Hvis vi bruker counter-eksempelet fra tidligere kunne et counter Slice sett slik ut:

1export const counterSlice = createSlice({
2    name: 'counter',
3    initialState: {
4        value: 0,
5    },
6    reducers: {
7        add(state) {
8            state.value++;
9        },
10        subtract(state) {
11            state.value--;
12        },
13        addByAmount(state, action: PayloadAction<number>) {
14            state.value += action.payload;
15        },
16    },
17});
18
19export const { add, subtract, addByAmount } = counterSlice.actions;
20export default counterSlice.reducer;


Her trenger man altså ingen switch-statements og man kan mutere state-verdien direkte.
Etter å ha laget Slicen eksporterer man Reduceren og Actionsene separat og importerer Reduceren inn i Store slik:

1import { configureStore } from@reduxjs/toolkit'
2import counterReducer from './counterSlice'
3
4export default configureStore({
5  reducer: {
6    counter: counterReducer
7  }
8})

Actionsene kan man nå få tilgang til fra hvor som helst, og sammen med React-Redux sine funksjoner useSelector, som velger state, og useDispatch som sender avgårde actions gjør det bruken av Redux til en lek!

I counter-eksempelet kunne disse ha blitt brukt slik:

1import { useSelector, useDispatch } from 'react-redux';
2import { useState } from 'react';
3import { add, subtract, addByAmount } from './counterSlice';
4
5export function Counter() {
6    const [customValue, setCustomValue] = useState(0);
7    const count = useSelector((state) => state.counter.value);
8    const dispatch = useDispatch();
9    return (
10        <div>
11            <button onClick={() => dispatch(add())}> + </button>
12            <p>{count}</p>
13            <button onClick={() => dispatch(subtract())}> - </button>
14            <input
15                value={customValue}
16                onChange={(e) => setCustomValue(e.target.value)}
17            />
18            <button onClick={() => dispatch(addByAmount(customValue))}>add</button>
19        </div>
20    );
21}

Konklusjon

Redux Toolkit er et fantastisk verktøy hvis man driver med state-management. Det er lettere for nybegynnere å forstå og for Redux-brukere er det lett å adaptere. Koden blir mye ryddigere, organisert og gir rett og slett mer mening 🤩

Andre tips

Redux Toolkit er også helt kompatibelt med Redux sine DevTools som kan lastes ned som en nettleser-utvidelse. Med dette verktøyet kan du se hva som fører til forskjellige actions og hvordan de skjer, samt koblingene mellom action og resultat.