useReducer

Yeom Jae Seon·2021년 1월 6일
0

React

목록 보기
2/3
post-thumbnail

useReducer


useReducer로 자주 사용하지는 않았지만 알아둘 필요가 충분히 있다고 생각함.

  • useState로 함수형 컴포넌트에서 State관리를 할수가 있다.
  • useReducer는 state를 업데이트하는 로직이 좀더 복잡할 때 사용하면 유용하다.
    const [state, dispatch] = useReducer(reducer, initState) 로 사용되고 여기서 state는 사용할 state이고 dispatch는 action을 실행시키는 함수이다. 이 action을 통해 state를 어떻게 업데이트할지 정할수 있다. reducer는 컴포넌트 외부에서 정의할 수 있는 state를 업데이트하는 로직이며
const reducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return ~~
    default:
      return;
  }
};

이런식으로 정의된다.
reducer함수의 첫번째 인자인 state는 업데이트 이전의 state이고 action은 dispatch함수가 발생시키는 action이다.
이 action을 통해서 어떤식으로 state를 업데이트할지 정할수 있다.

이는 redux에서도 사용하는 action을 발생시키는 dispatch함수를 통해서 reducer함수에서 이전 state와 action으로 새로운(업데이트 된) state를 리턴해주는 방시과 같다.

  • useReducer를 사용하면 state업데이트 로직을 컴포넌트 외부에 분리 가능 - state 업데이트로직이 모듈화가 가능해진것.
  • reducer함수에서 action을 dispatch시킴으로써 state를 업데이트 하는 것은 단순히 useState에서 setState로 업데이트 시키는 것보다 가독성이 높고 관리사 용이해지는 장점이 있다.

그리고 추가로 useReducer의 세번째 인자에는 초기화하는 함수가 들어갈 수 있는데 이는 reducer함수 외부에서 초기 state를 설정하는 로직이 존재할수 있다는 것이고 단순히 reducer에서만 state를 업데이트하기보단 그 외부에 state 업데이트 로직의 추가로 더 다양한 일을 하게 도와줄수 있다.

예시를 확인해보자

코드

import React, { useReducer, useRef } from "react";
import "./styles.css";

const initState = [];

const ACTIONS = {
  ADD_TODO: "ADD_TODO",
  DELETE_TODO: "DELETE_TODO",
  TOGGLE_TODO: "TOGGLE_TODO"
};

let id = 0;

const reducer = (state, action) => {
  switch (action.type) {
    case ACTIONS.ADD_TODO:
      return [
        ...state,
        { id: action.payload.id, thing: action.payload.thing, checked: false }
      ];
    case ACTIONS.DELETE_TODO:
      return state.filter((todo) => todo.id !== action.payload.id);
    case ACTIONS.TOGGLE_TODO:
      return state.map((todo) => {
        if (todo.id === action.payload.id) {
          return !todo.checked
            ? { ...todo, checked: true }
            : { ...todo, checked: false };
        }
        return todo;
      });
    default:
      return;
  }
};

export default function App() {
  const inputRef = useRef();
  const [state, dispatch] = useReducer(reducer, initState);

  const addTodo = (e) => {
    e.preventDefault();
    const newTodo = inputRef.current.value;
    dispatch({
      type: ACTIONS.ADD_TODO,
      payload: { id: ++id, thing: newTodo }
    });
    inputRef.current.value = "";
    inputRef.current.focus();
  };

  const deleteTodo = (id) => {
    dispatch({ type: ACTIONS.DELETE_TODO, payload: { id } });
  };

  const toggleTodo = (id) => {
    dispatch({ type: ACTIONS.TOGGLE_TODO, payload: { id } });
  };

  return (
    <>
      <form onSubmit={addTodo}>
        <input type="text" ref={inputRef} />
        <button>추가</button>
      </form>
      <ul>
        {state.map((todo) => {
          return (
            <li key={todo.id}>
              <span
                style={
                  todo.checked ? { textDecorationLine: "line-through" } : null
                }
              >
                {todo.thing}
              </span>
              <button
                onClick={() => {
                  deleteTodo(todo.id);
                }}
              >
                삭제
              </button>
              <button
                onClick={() => {
                  toggleTodo(todo.id);
                }}
              >
                toggle
              </button>
            </li>
          );
        })}
      </ul>
    </>
  );
}

요즘에 자주 사용하지 않아서 익숙치 않던던 액션을 dispatch시켜서 reducer에서 state업데이트하는 방식을 다시금 사용하게되어 좋았다.

0개의 댓글