Vzorec Reducer sa skladá z dvoch častí: z počiatočného stavu a z funkcie, ktorá sa najčastejšie volá dispatch, ale môže mať hocijaké meno.
const initialState = 0; const reducer = (state, action) => { switch (action) { case 'increment': return state + 1; case 'decrement': return state - 1; case 'reset': return 0; default: throw new Error('Error message'); } };
Počiatočný stav môže byť jednoduchý typ alebo zložitý objekt.
Príklad použitia Reducer vo funkcii:
const Komponent1 = () => {
const [count, dispatch] = useReducer(reducer, initialState);
return (
<div>
{count}
<button onClick={() => dispatch('increment')}>+1</button>
<button onClick={() => dispatch('decrement')}>-1</button>
<button onClick={() => dispatch('reset')}>reset</button>
</div>
);
};
V tomto prípade neprenášam stav do iných modulov, ale len využívam v rámci jednej funkcie, na čo by mi stačil aj useState.
Tu je príklad na reducer, ktorý modifikuje zložitejší objekt a zároveň aj spracovanie chyby:
const initialState = {
counter1: 0,
counter2: 0,
};
const reducer = (state, action) => {
switch (action.type) {
case 'increment1':
return { ...state, counter1: state.counter1 + 1 };
case 'decrement1':
return { ...state, counter1: state.counter1 - 1 };
case 'set1':
return { ...state, counter1: action.count };
case 'increment2':
return { ...state, counter2: state.counter2 + 1 };
case 'decrement2':
return { ...state, counter2: state.counter2 - 1 };
case 'set2':
return { ...state, counter2: action.count };
default:
throw new Error('Error message');
}
};
Tu je použitie vo funkčnom komponente:
const Komponent2 = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<div>
{state.count1}
<button onClick={() => dispatch({ type: 'increment1' })}>+1</button>
<button onClick={() => dispatch({ type: 'decrement1' })}>-1</button>
<button onClick={() => dispatch({ type: 'set1', count: 0 })}>reset</button>
</div>
<div>
{state.count2}
<button onClick={() => dispatch({ type: 'increment2' })}>+1</button>
<button onClick={() => dispatch({ type: 'decrement2' })}>-1</button>
<button onClick={() => dispatch({ type: 'set2', count: 0 })}>reset</button>
</div>
</>
);
};
Problém reducerov je, že sú tzv. čisté funkcie (pure functions) pretože nemajú vnútorný stav (stateless). Aby sme zapamätali stav, použijeme Context:
const CountContext = React.createContext();
const CountProvider = ({ children }) => {
const contextValue = useReducer(reducer, initialState);
return (
<CountContext.Provider value={contextValue}>
{children}
</CountContext.Provider>
);
};
const useCount = () => {
const contextValue = useContext(CountContext);
return contextValue;
};
V tomto kóde užívateľská funkcia vracia context a ten obsahuje dispatch funkciu aj stav.
Nasledujúci kód ukazuje, ako sa dá využiť Consumer.
const Counter = () => {
const [count, dispatch] = useCount();
return (
<div>
{count}
<button onClick={() => dispatch({ type: 'increment' })}>+1</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-1</button>
<button onClick={() => dispatch({ type: 'set', count: 0 })}>reset</button>
</div>
);
};
Pôvodný článok: https://medium.com/crowdbotics/how-to-use-usereducer-in-react-hooks-for-performance-optimization