Jak funguje React Hook useReducer

UseState jste tedy používali efektivně a pomalu eliminovali všechny komponenty vaší třídy. Ale teď se vaše funkční komponenty začínají nafukovat všemi vašimi voláními useState. Možná váš kód vypadá trochu takto?

const [userName, setUserName] = useState('');
const [password, setPassWord] = useState('');
const [email, setEmail] = useState('');
const [employmentStatus, setEmploymentStatus] = useState('Student');
const [community, setCommunity] = useState('');
const [loggedIn, setLoggedIn] = userState(false)

useState je skvělé, když máte ke sledování jen pár věcí, ale jakmile budete mít spoustu věcí ke sledování, začne se vám to vymykat z rukou. Jistě byste mohli nastavit svůj stav na objekt a jen aktualizovat pole, které chcete změnit... Možná jste něco takového udělali?

const state [state, setState] = useState({username: '', password: '', email: ''});

setState({...state, username: 'Daniel'});

Ale to se začne hroutit, až budete mít vnořené objekty, a my se chceme vyřádit a udržet náš kód pevný. Pojďme se tedy bavit o useReducer. Pokud jste někdy používali React Redux, některé z toho, co se chystáme udělat, vám mohou připadat velmi povědomé, ale pokud ne, nebojte se. useReducer je neuvěřitelně podobný použití snížit v obyčejném starém běžném Javascriptu.

Začněme jednoduchým příkladem, který by bylo pravděpodobně jednodušší vyřešit pomocí useState, ale tento příklad nám ukáže, jak useReducer funguje.

Chtěli bychom provést přírůstek počítadla pomocí useReducer.

import React, {useReducer} from 'react';

const simpleCounter = () => {
  const [counter, dispatch] = useReducer(reducer, 0);
  return (
    <div>
      Counter: {counter}
      <span onClick={() => dispatch('increase')}>Increase</span>
      <span onClick={() => dispatch('decrease')}>Decrease</span>
    </div>
  );
};

const reducer = (oldValue, action) => {
  switch(action) {
    case 'increase': return oldValue + 1;
    case 'decrease': return oldValue - 1;
    default: return oldValue;
  }
};

Za prvé, musíme importovat useReducer z React, mohli bychom jednoduše nazvat React.useReducer, ale místo toho se pojďme bavit destrukcí.

Pak musíme zavolat useReducer. Jako své parametry bere redukční funkci a počáteční hodnotu a vrací pole, které ničíme a které obsahuje aktuální stav a funkci odeslání.

Funkce odeslání zavolá reduktor se dvěma parametry. První bude aktuální stav a druhý budou jakékoli argumenty, které předáte do funkce odeslání. Je dobrou konvencí volat tento druhý parametr action.

Takže zde naše funkce redukce pouze bere starou hodnotu čítače jako svůj první parametr a akci, kterou na něm chcete provést, jako druhý parametr, v tomto případě je to 'increment' nebo 'decrement' a poté vrátí novou hodnotu pro čítač. Pamatujte, že snížení Javascriptu musí vždy vrátit hodnotu, kterou akumuluje, takže totéž platí zde. Cokoli vrátíte, bude nový stav, nebo v tomto případě proměnná čítače.

Dobře, ten příklad byl trochu jednoduchý, takže ho trochu posílíme. Toto bude také příliš složité řešení velmi jednoduchého problému, ale pojďme na to, protože to začne vypadat jako něco, co skutečně uvidíte v reálném světě.

Předpokládejme, že máme v počátečním stavu nějaké další proměnné, jiné než jen čítač, takže nemůžeme jen tak vrátit nový čítač v našem reduktoru.

const initialState = {
  counter: 0,
  //...more variables we don't want to overwrite
};

const complexCounter = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      Counter: {state.counter}
      <span onClick={() => dispatch({type: 'increase'})}>Increase</span>
      <span onClick={() => dispatch({type: 'decrease'})}>Decrease</span>
    </div>
  );
};

const reducer = (prevState, action) => {
  switch(action.type) {
    case 'increase': return {...prevState, counter: prevState.counter + 1};
    case 'decrease': return {...prevState, counter: prevState.counter - 1};
    default: return prevState;
  }
};

Jsou zde pouze dva rozdíly, jeden je ten, že místo pouhého předávání řetězce 'increase' nebo 'decrease' , předáváme objekt, který má typ toho, co chceme dělat. Toto je vzorec, který uvidíte, pokud začnete používat Redux, ale nedělejte si s tím příliš velké starosti, jen vězte, že je dobré si zvyknout na to, že tento vzorec je spojen s reduktory.

Další změnou je, že nyní nevracíme pouze proměnnou čítače z našeho reduktoru, ale vracíme celý objekt. Takže použijeme operátor spread, abychom získali kopii starého stavu a pak přepsali proměnnou, kterou chceme změnit, v tomto případě čítač.

V tomto příkladu to funguje dobře, ale s tím, jak vkládáme objekty do objektů, to bude stále složitější a obtížnější. V praktickém příkladu by tedy pravděpodobně bylo lepší aktualizovat proměnnou, kterou chcete změnit, a poté vrátit stav s touto změněnou aktualizovanou hodnotou. Takže by to změnilo náš reduktor tak, aby vypadal jako příklad níže.

Pro tento příklad předpokládejme, že čítač je objekt, který má klíč hodnoty, kde je uložena hodnota čítače.

const reducer = (prevState, action) => {
  const updatedCounter = {...prevState.counter};
  switch(action.type) {
    case 'increase':
      updatedCounter.value++;
      break;
    case 'decrease':
      updatedCounter.value--;
      break;
    default: return prevState;
  }
  return {...prevState, counter: updatedCounter}
};

Zde jsme vytvořili kopii proměnné čítače ve stavu a pouze zvýšíme nebo snížíme hodnotu naší nové proměnné. Pak můžeme vrátit aktualizované počítadlo a nemusíme se starat o přepsání vnořených hodnot.

Tento reduktor by zjevně nefungoval tak, jak je v současné době stavěn, pro nic jiného, ​​než je výměna pultu, ale věřím, že to vystihuje myšlenku. Pokud chcete vidět, jak useReducer funguje v praktické aplikaci, podívejte se, jak jej používat ve formě v této sérii článků.