useReducer

훈나무·2022년 12월 7일
0

flux pattern

목록 보기
3/7
post-thumbnail

Flux 패턴에서 자주 쓰이는 reducer, dispatch 등을 useReducer를 사용해서 알아보겠습니다.

⭐counter컴포넌트


먼저 counter 컴포넌트를 만들어 보겠습니다.

import { useState } from "react";
import Button from "../components/Button";
import Panel from "../components/Panel";

function CounterPage() {
  const [count, setCount] = useState(10);
  const [valueToAdd, setValueToAdd] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };
  const decrement = () => {
    setCount(count - 1);
  };
  const reset = () => {
    setCount(0);
  };
  const handleChange = (e) => {
    const value = parseInt(e.target.value) || 0;
    setValueToAdd(+value);
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    setCount(count + valueToAdd);
    setValueToAdd(0);
  };

  return (
    <Panel className="m-3">
      <h1 className="text-3xl py-6 ">
        Count is{" "}
        <span className="text-5xl font-bold text-indigo-500">{count}</span>
      </h1>
      <div className="flex flex-row">
        <Button onClick={increment}>Increment</Button>
        <Button onClick={decrement}>Decrement</Button>
        <Button onClick={reset}>reset</Button>
      </div>

      <form onSubmit={handleSubmit}>
        <label>Add a lot!</label>
        <input
          value={valueToAdd}
          onChange={handleChange}
          type="number"
          className="p-1 m-3 bg-gray-50 border border-gray-300"
        />
        <Button>Add it!</Button>
      </form>
    </Panel>
  );
}

export default CounterPage;

🛠️useReducer 적용


useState 로 만들어진 컴포넌트를 useReducer 를 사용해서 리팩토링 해보겠습니다.

import { useReducer } from "react";
import Button from "../components/Button";
import Panel from "../components/Panel";
import produce from "immer";

const INCREMENT_COUNT = "increment";
const DECREMENT_COUNT = "decrement";
const RESET = "reset";
const SET_VALUE_TO_ADD = "change_value_to_add";
const ADD_VALUE_TO_COUNT = "add_value_to_count";

const reducer = (state, action) => {
  switch (action.type) {
    case INCREMENT_COUNT:
      state.count += 1;
      return;
    case DECREMENT_COUNT:
      state.count -= 1;
      return;
    case RESET:
      state.count = 0;
      return;
    case SET_VALUE_TO_ADD:
      state.valueToAdd = action.payload;
      return;
    case ADD_VALUE_TO_COUNT:
      state.count = state.count + state.valueToAdd;
      state.valueToAdd = 0;
      return;
    default:
      return;
  }
};

function CounterPage() {
  const [state, dispatch] = useReducer(produce(reducer), {
    count: 0,
    valueToAdd: 0,
  });

  const increment = () => dispatch({ type: INCREMENT_COUNT });
  const decrement = () => dispatch({ type: DECREMENT_COUNT });
  const reset = () => dispatch({ type: RESET });
  const handleChange = (e) => {
    const value = parseInt(e.target.value) || 0;
    dispatch({ type: SET_VALUE_TO_ADD, payload: value });
  };
  const handleSubmit = (e) => {
    dispatch({ type: ADD_VALUE_TO_COUNT });
    e.preventDefault();
  };

  return (
    <Panel className="m-3">
      <h1 className="text-3xl py-6 ">
        Count is{" "}
        <span className="text-5xl font-bold text-indigo-500">
          {state.count}
        </span>
      </h1>
      <div className="flex flex-row">
        <Button onClick={increment}>Increment</Button>
        <Button onClick={decrement}>Decrement</Button>
        <Button onClick={reset}>reset</Button>
      </div>

      <form onSubmit={handleSubmit}>
        <label>Add a lot!</label>
        <input
          value={state.valueToAdd}
          onChange={handleChange}
          type="number"
          className="p-1 m-3 bg-gray-50 border border-gray-300"
        />
        <Button>Add it!</Button>
      </form>
    </Panel>
  );
}

export default CounterPage;

실행결과는 완벽하게 동일하지만, 이전에 배웠던 contextApi와 함께 사용하면, redux 와 비슷한 설정이 가능합니다.

useReducercontextApi 에 대해서 이해했다면, redux 또한 무리없이 이해할 수 있습니다.

🎨실행화면


profile
프론트엔드 개발자 입니다

0개의 댓글