Categories
Nezaradené

ReactJS s useContext a useReducer

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