Frontend Academy · Oppitunti

useReducer monimutkaiseen tilaan

Mallinna tilasiirtymiä reducer-funktiolla, lähetä action-objekteja dispatchilla ja suosi useReduceria useStateen verrattuna, kun tilalogiikka monimutkaistuu

Oppitunti 2/412 vaihetta

useReducer monimutkaiseen tilaan on ilmainen Frontend Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Frontend Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Frontend Academy-kurssilla on yhteensä 4 oppituntia.

Kun useState ei riitä

Kun tilasiirtymiin liittyy monimutkaista logiikkaa, useita toisiinsa liittyviä arvoja tai tilanteita, joissa uusi tila riippuu edellisestä tilasta ei-triviaalilla tavalla, useReducer on selkeämpi valinta kuin useat useState-kutsut.

Reducer-funktion malli

Reducer on puhdas funktio: (state, action) => newState. Se saa nykyisen tilan ja action-olion ja palauttaa seuraavan tilan. Älä muokkaa tilaa — palauta aina uusi objekti.

type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset'; payload: number };

function counterReducer(state: number, action: Action): number {
  switch (action.type) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset':     return action.payload;
    default: return state;
  }
}

useReducerin syntaksi

useReducer(reducer, initialState) palauttaa nykyisen tilan ja dispatch-funktion. Käynnistä tilasiirtymä kutsumalla dispatchia action-olion kanssa.

function Counter() {
  const [count, dispatch] = useReducer(counterReducer, 0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </div>
  );
}

Tyypitetyt actionit — diskriminoidut union-tyypit

Käytä actioneille TypeScriptin diskriminoituja union-tyyppejä, jotta saat reducerin switch-lauseeseen kattavan tyyppitarkistuksen.

type CartAction =
  | { type: 'ADD_ITEM'; item: CartItem }
  | { type: 'REMOVE_ITEM'; id: string }
  | { type: 'SET_QUANTITY'; id: string; qty: number }
  | { type: 'CLEAR' };

Monimutkaisen tilan esimerkki: ostoskori

Ostoskori, jossa on lisäämis-, poistamis- ja määränpäivitystoiminnot, on täydellinen käyttötapaus useReducerille.

interface CartState {
  items: CartItem[];
  total: number;
}

function cartReducer(state: CartState, action: CartAction): CartState {
  switch (action.type) {
    case 'ADD_ITEM': {
      const exists = state.items.find(i => i.id === action.item.id);
      if (exists) {
        const items = state.items.map(i =>
          i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i
        );
        return { ...state, items, total: calcTotal(items) };
      }
      const items = [...state.items, { ...action.item, qty: 1 }];
      return { ...state, items, total: calcTotal(items) };
    }
    case 'CLEAR': return { items: [], total: 0 };
    default: return state;
  }
}

Dispatch on vakaa

dispatch-funktio on vakaa — se ei muutu renderöintikertojen välillä. Voit välittää sen turvallisesti propina tai käyttää sitä useEffect-riippuvuutena ilman tarpeettomia uudelleenkäynnistyksiä.

useReducerin ja useContextin yhdistäminen

Tehokas malli: konteksti tarjoaa sekä tilan että dispatchin, jolloin mikä tahansa kontekstin käyttäjä voi lukea tilaa tai lähettää actioneita ilman propien välittämistä komponenttiketjun läpi.

const CartContext = createContext<{ state: CartState; dispatch: Dispatch<CartAction> } | null>(null);

function CartProvider({ children }: { children: React.ReactNode }) {
  const [state, dispatch] = useReducer(cartReducer, { items: [], total: 0 });
  return <CartContext.Provider value={{ state, dispatch }}>{children}</CartContext.Provider>;
}

useReducer vai useState

Valitse useReducer, kun tilassa on useita aliarvoja, seuraava tila riippuu edellisestä monimutkaisilla tavoilla, tilasiirtymiä on paljon ja ne halutaan nimetä eksplisiittisesti tai haluat testata tilalogiikkaa komponentista erillään.

Reducerien testaaminen erillään

Koska reducerit ovat puhtaita funktioita, niitä on erittäin helppo testata ilman yhdenkään komponentin renderöimistä.

test('increment action increases count', () => {
  expect(counterReducer(0, { type: 'increment' })).toBe(1);
  expect(counterReducer(5, { type: 'increment' })).toBe(6);
});

test('reset action sets count to payload', () => {
  expect(counterReducer(42, { type: 'reset', payload: 0 })).toBe(0);
});

Immer muuttumattomiin päivityksiin

immer-kirjaston avulla voit kirjoittaa muuttavalta näyttävää koodia, joka tuottaa uuden muuttumattoman tilan. Se on hyödyllinen reducerien monimutkaisissa sisäkkäisten objektien päivityksissä.

Pikatarkistus

Mikä on reducer-funktion allekirjoitus?

Kertaus: useReducer

(state, action) => newState — puhdas, ei muutoksia. useReducer(reducer, initial) palauttaa [state, dispatch]. Käytä turvallisuuden lisäämiseksi diskriminoituja union-tyyppejä actioneille. dispatch on vakaa. Se sopii erinomaisesti monimutkaiseen tilaan, jossa on paljon tilasiirtymiä. Yhdistä se useContextiin globaalin tilan hallintaa varten. Testaa reducerit erillään puhtaina funktioina.

Aloita maksutta

Opi HTML tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
41
Oppitunnit
163

Usein kysytyt kysymykset

Onko oppitunti ”useReducer monimutkaiseen tilaan” ilmainen?

Kyllä – oppitunnin ”useReducer monimutkaiseen tilaan” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Frontend Academy-kurssin, päivitä CoddyKit PROhon. Frontend Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”useReducer monimutkaiseen tilaan”?

Mallinna tilasiirtymiä reducer-funktiolla, lähetä action-objekteja dispatchilla ja suosi useReduceria useStateen verrattuna, kun tilalogiikka monimutkaistuu Harjoittelet Frontend Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Frontend Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Frontend Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”useReducer monimutkaiseen tilaan”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Frontend Academy-oppitunnilla?

Kyllä. Jokainen Frontend Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. useContext globaalin tilan hallintaan
  2. useReducer monimutkaiseen tilaan
  3. useMemo ja useCallback suorituskyvyn parantamiseen
  4. Mukautetut hookit: uudelleenkäytettävän logiikan eriyttäminen
← Takaisin: Frontend Academy