UseReducer jest alternatywą dla useState. Działa lepiej, gdy mamy złożoną logikę stanu, która obejmuje wiele podwartości (np. jeśli stan jest obiektem zagnieżdżonym) lub gdy następny stan zależy od poprzedniego. Hook UseReducer przyjmuje reduktor będący funkcją o sygnaturze (stan, akcja) => nowyStan i zwraca aktualny stan w parze z metodą dispatch:
const [state, dispatch] = useReducer(reducer, initialArg, init);
Oznacza to, że pierwszy parametr hooka useReucer to funkcja, w której możesz użyć bardziej skomplikowanych zależności do zmiany bardziej skomplikowanego stanu. Drugi parametr natomiast to inicjalizująca wartość stanu.
const switchOption = (state, action) => {
switch (action.type) {
case 'add':
return {count: state.count + 1, color: "green"};
case 'substract':
return {count: state.count - 1, color: "red"};
case "reset":
return action.setInitState;
default:
return {count: state};
}
}
// stan zapisany za pomocą useReducer
const [state, dispatch] = useReducer(
switchOption,
{count: initialCount, color: "gray"}
);
Zobaczmy to na przykładzie. Mamy licznik, który pokazuje liczby od 0 (nasz stan początkowy) oraz dwa przyciski: +1 i -1. Kiedy klikamy przycisk +1, licznik zmienia swoją wartość i kolor na zielony, kiedy klikamy przycisk -1, licznik zmienia swoją wartość i kolor na czerwony. Początkowy kolor licznika to szary, a licznik otrzymuje ten kolor, kiedy klikamy trzeci przycisk o nazwie reset, który również resetuje licznik do 0.
Komponent zwraca nasze przyciski:
return (
<div className="App">
<p> Counter: <span style={{color: counter.color }}> {counter.count} </span></p>
<button onClick={() => setCounter({type: "add"})} > +1 </button>
<button onClick={() => setCounter({type: "substract"})} > -1 </button>
<div>
<button onClick={() => setCounter({type: "reset", setInitState: initState})} > reset </button>
</div>
</div>
);
Inicjalizujemy stan:
const initState = {count: 0, color: "gray"}
// state - Declaring new state variable, called "counter" and initial count state
const [counter, setCounter] = useReducer(switchOption, initState);
Zobacz jak to działa klikając DEMO
Cały komponent wygląda tak:
import React, { useReducer } from 'react';
const HookExample = () => {
const switchOption = (state, action) => {
switch (action.type) {
case 'add':
return {count: state.count + 1, color: "green"};
case 'substract':
return {count: state.count - 1, color: "red"};
case "reset":
return action.setInitState;
default:
return {count: state};
}
}
const initState = {count: 0, color: "gray"}
// state - Declaring new state variable, called "counter" and initial count state
const [counter, setCounter] = useReducer(switchOption, initState);
return (
<div className="App">
<p> Counter: <span style={{color: counter.color }}> {counter.count} </span></p>
<button onClick={() => setCounter({type: "add"})} > +1 </button>
<button onClick={() => setCounter({type: "substract"})} > -1 </button>
<div>
<button onClick={() => setCounter({type: "reset", setInitState: initState})} > reset </button>
</div>
</div>
);
}
export default HookExample;
Zobacz DEMO i sprawdź, jak działa hook useReducer
Kod do tego postu możesz naleźć tu: https://github.com/love-coding-pl/React-Hooks-Examples/tree/Hook-2-useReducer