React Native Academy · Oppitunti

useReducer monimutkaiseen tilalogiikkaan

Korvatkaa useat useState-kutsut yhdellä useReducerilla, kirjoittakaa reducer-funktio toimintotyyppeineen ja lähettäkää toimintoja käyttöliittymän tapahtumista.

Oppitunti 2/413 vaihetta

useReducer monimutkaiseen tilalogiikkaan on ilmainen React Native Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu React Native Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. React Native Academy-kurssilla on yhteensä 4 oppituntia.

Miksi useReducer?

Kun komponentissa on useita toisiinsa liittyviä päivityksiä tekeviä useState-kutsuja, logiikkaa voi olla vaikea seurata. useReducer keskittää kaikki tilasiirtymät yhteen reducer-funktioon, mikä helpottaa monimutkaisen tilalogiikan ymmärtämistä, testaamista ja virheenkorjausta – kyseessä on sama malli, jonka Redux teki suosituksi.

Reducer-funktio

Reducer on puhdas funktio, joka vastaanottaa nykyisen tilan ja action-olion ja palauttaa seuraavan tilan. Sen on oltava puhdas: ei sivuvaikutuksia, API-kutsuja tai vastaanotetun tilaolion muuttamista. Palauttakaa uuden tilan sisältävä uusi olio. action.type-merkkijono ilmaisee, mikä siirtymä suoritetaan.

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

useReducer-kutsun tekeminen

useReducer vastaanottaa reducer-funktion ja alkuperäisen tilan ja palauttaa arvon [state, dispatch]. state on tilan nykyinen arvo. dispatch-funktio lähettää actionin reducerille tilasiirtymän käynnistämiseksi ja uudelleenrenderöinnin ajoittamiseksi.

import { useReducer } from 'react';

const initialState = { count: 0 };

function Counter() {
  const [state, dispatch] = useReducer(counterReducer, initialState);

  return (
    <View>
      <Text>Count: {state.count}</Text>
      <Button title='+' onPress={() => dispatch({ type: 'increment' })} />
      <Button title='-' onPress={() => dispatch({ type: 'decrement' })} />
      <Button title='Reset' onPress={() => dispatch({ type: 'reset' })} />
    </View>
  );
}

Payloadin välittäminen actioneissa

Actionit voivat sisältää lisätietoja payload-ominaisuudessa. Reducer lukee arvon action.payload tietääkseen siirtymän yksityiskohdat. Esimerkiksi 'addItem'-action voi sisältää uuden kohteen tiedot payloadissaan, jolloin reducer lisää kohteen tilan items-taulukkoon.

function listReducer(state, action) {
  switch (action.type) {
    case 'addItem':
      return { items: [...state.items, action.payload] };
    case 'removeItem':
      return { items: state.items.filter((i) => i.id !== action.payload.id) };
    default:
      return state;
  }
}

// Dispatch with payload
dispatch({ type: 'addItem', payload: { id: '1', text: 'Buy milk' } });

Ostoskorin hallinta

Ostoskori on hyvä käytännön esimerkki useReducer-hookin käytöstä, koska siihen liittyy useita toisiinsa liittyviä tilasiirtymiä: kohteiden lisääminen ja poistaminen, määrien päivittäminen sekä ostoskorin tyhjentäminen. Kukin action-tyyppi vastaa reducer-funktiossa selkeää ja testattavaa siirtymää.

const initialCartState = { items: [], total: 0 };

function cartReducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return {
        items: [...state.items, action.payload],
        total: state.total + action.payload.price,
      };
    case 'CLEAR':
      return initialCartState;
    default:
      return state;
  }
}

Tilan lazy-alustus

Välittäkää useReducer-hookille kolmas argumentti – init-funktio – tilan alkuarvon laskemiseksi lazy-menetelmällä. React kutsuu tällöin funktiota init(initialArg) sen sijaan, että käyttäisi initialArg-arvoa suoraan. Tämä on hyödyllistä, kun alkuperäinen tila johdetaan propista tai sen laskeminen on kallista.

function init(initialCount) {
  return { count: initialCount };
}

function Counter({ startCount }) {
  const [state, dispatch] = useReducer(
    counterReducer,
    startCount, // passed to init
    init         // called once on mount
  );
}

useReducer ja useState

Käyttäkää useState-hookia yksinkertaisiin, toisistaan riippumattomiin arvoihin (totuusarvo, merkkijono tai luku). Valitkaa useReducer, kun tilasiirtymät riippuvat useista arvoista samanaikaisesti, kun seuraava tila riippuu nykyisestä tilasta monimutkaisella tavalla tai kun haluatte koota kaiken tilalogiikan yhteen testattavaan funktioon.

// useState — fine for simple independent values
const [name, setName] = useState('');
const [age, setAge] = useState(0);

// useReducer — better when these fields relate to each other
const [userForm, dispatch] = useReducer(userFormReducer, {
  name: '',
  age: 0,
  isValid: false,
});

Lomakkeen tila useReducer-hookilla

Monimutkainen rekisteröitymislomake, jossa on useita kenttiä ja validointilogiikkaa, hyötyy useReducer-hookista. Määritelkää action-tyypit, kuten 'CHANGE_FIELD', 'VALIDATE' ja 'SUBMIT'. Reducer käsittelee kaikki kenttien päivitykset ja validoinnin yhdessä paikassa sen sijaan, että ne olisi hajautettu useisiin useState-settereihin ja useEffect-kutsuihin.

function formReducer(state, action) {
  switch (action.type) {
    case 'CHANGE_FIELD':
      return {
        ...state,
        values: { ...state.values, [action.field]: action.value },
        errors: { ...state.errors, [action.field]: null },
      };
    case 'SET_ERROR':
      return { ...state, errors: { ...state.errors, ...action.errors } };
    default:
      return state;
  }
}

Reducerin testaaminen erillään

Koska reducerit ovat puhtaita funktioita ilman sivuvaikutuksia, niitä on erittäin helppo testata yksikkötesteillä. Kutsukaa reduceria suoraan tilan ja actionin kanssa ja tarkistakaa palautettu tila. Komponenttia ei tarvitse liittää eikä mitään APIa tarvitse simuloida logiikan testaamista varten.

// Pure unit test — no React needed
test('increment action increases count by 1', () => {
  const state = { count: 5 };
  const next = counterReducer(state, { type: 'increment' });
  expect(next.count).toBe(6);
});

test('reset returns count to 0', () => {
  const state = { count: 100 };
  const next = counterReducer(state, { type: 'reset' });
  expect(next.count).toBe(0);
});

useReducerin yhdistäminen useContextiin

Tehokas malli on yhdistää useReducer ja useContext pienen Redux-tyyppisen globaalin tilavaraston rakentamiseksi. Viekää dispatch-funktio kontekstin kautta, jotta mikä tahansa jälkeläiskomponentti voi lähettää actioneita ilman propien välittämistä komponentilta toiselle. Näin keskivaikeisiin sovelluksiin ei tarvitse asentaa kolmannen osapuolen kirjastoa.

const StoreContext = createContext(null);
const DispatchContext = createContext(null);

export function StoreProvider({ children }) {
  const [state, dispatch] = useReducer(appReducer, initialState);
  return (
    <StoreContext.Provider value={state}>
      <DispatchContext.Provider value={dispatch}>
        {children}
      </DispatchContext.Provider>
    </StoreContext.Provider>
  );
}

Actionien lähettäminen useista komponenteista

Kun dispatch-funktio on saatavilla kontekstin kautta, mikä tahansa sisäkkäinen komponentti voi käynnistää tilasiirtymiä vastaanottamatta propseja. Tuokaa useContext(DispatchContext)-hook, kutsukaa dispatchia sopivan action-tyypin kanssa, ja reducer käsittelee päivityksen keskitetysti. Tämä malli skaalautuu hyvin sovelluksen kasvaessa.

function AddToCartButton({ product }) {
  const dispatch = useContext(DispatchContext);

  return (
    <Button
      title='Add to Cart'
      onPress={() => dispatch({ type: 'ADD', payload: product })}
    />
  );
}

Pikatarkistus

Testatkaa, miten hyvin ymmärrätte tämän oppitunnin useReducer-hookin käytön monimutkaisessa tilalogiikassa.

Oppitunnin kertaus

Tässä oppitunnissa opitte, että useReducer keskittää tilasiirtymät puhtaaseen reducer-funktioon, actioneita lähetetään tyypin ja valinnaisen payloadin kanssa siirtymien käynnistämiseksi ja useReducer voidaan yhdistää useContextiin skaalautuvaksi globaalin tilan malliksi ilman Reduxia. Seuraavaksi tutustumme useCallback- ja useMemo-hookeihin suorituskyvyn optimointia varten.

Aloita maksutta

Opi JavaScript 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
30
Oppitunnit
120

Usein kysytyt kysymykset

Onko oppitunti ”useReducer monimutkaiseen tilalogiikkaan” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa React Native Academy-oppimispolun 3 oppituntia, myös oppitunnin “useReducer monimutkaiseen tilalogiikkaan”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. React Native Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”useReducer monimutkaiseen tilalogiikkaan”?

Korvatkaa useat useState-kutsut yhdellä useReducerilla, kirjoittakaa reducer-funktio toimintotyyppeineen ja lähettäkää toimintoja käyttöliittymän tapahtumista. Harjoittelet React Native Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni React Native Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin React Native 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 tilalogiikkaan”-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ä React Native Academy-oppitunnilla?

Kyllä. Jokainen React Native 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. useRef DOM-solmuille ja muuttuviin arvoihin
  2. useReducer monimutkaiseen tilalogiikkaan
  3. useCallback ja useMemo suorituskyvyn parantamiseen
  4. Mukautettujen hookien kirjoittaminen
← Takaisin: React Native Academy