[7주차] Redux 말고 useReducer

voyager 999·2024년 2월 5일

React

목록 보기
14/27

리액트 프로젝트를 만들 때, 한 컴포넌트에서 선언 및 사용되는 state를 다른 컴포넌트에서 사용하기 위해 prop-drilling 방식을 활용할 수 있다. 그런데 이 방식은 부모 컴포넌트에서 자식 컴포넌트로 단방향으로만 state를 전달 가능하고, 그 역방향 혹은 동일 레벨상에서의 state 전달이 불가능하다. 또한 부모 - 자식 - 그 자식의 자식 - 그 자식의 자식 ... 처럼 구조의 뎁스가 깊어질수록 디버깅 및 추적의 어려움이 있다.

useContext hook을 사용하면, 특정 context의 범위 아래에 있는 모든 컴포넌트들은 prop-drilling 과정 없이 필요할 때 원하는대로 state에 접근 및 setState를 할 수 있다. 그러나 최상단의 state를 업데이트 하면 하위의 모든 컴포넌트가 함께 리렌더링되기 때문에 성능에 악영향을 줄 수 있다는 문제가 있어 상태 변화가 거의 일어나지 않을 것으로 예상되는 값을 전달할 때 적합하다.

(useMemo를 사용하여 리렌더링 비용을 최적화 할 수도 있다.)


useReducer

Redux가 나온 이후에 React 자체 Hook으로 추가된 기능이라고 한다. 그래서 reducer, action, dispatch 등 관련 개념과 사용 방법이 Redux와 거의 같다.

이미지 출처: 링크텍스트


1. state 선언하기

const [state, dispatch] = useReducer(reducer, initialState);


2. Reducer 만들기 (payload 없는 경우):
reducer는 인자로 state와 action객체를 받아 state를 어떤 식으로 변화시킬 것인지를 미리 설정해 두는 곳이다.

import React, { useReducer } from 'react';

function reducer(state, action) {
   switch (action.type) {
      case 'FIRST_CASE':
         return state + 1;
      case 'SECOND_CASE:
         return state - 1;
      default:
         return state;
   }
}

3. Reducer 사용하기:
state의 변화를 일으키고자 하는 이벤트에 함수를 걸어주고 dispatch를 실행시켜 action 객체를 reducer로 던져준다. 이 때 reducer는 전달받은 action의 type에 따라 payload만큼 state를 변화시키고, 이에 따라 화면이 재렌더링 된다.

function Counter() {
   const [state, dispatch] = useReducer(reducer, 0);
   
   const Increase = () => {
      dispatch({type: 'FIRST_CASE'});
   };
   
   const Decrease = () => {
      dispatch({type: 'SEOCOND_CASE'});
   };
   
   return (
      <>
         <button onClick={Increase}> +1 </button>
         <button onClick={Decrease}> -1 </button>
      </>
   );
}

관리하는 값이 단순한 숫자, 문자열이거나 boolean값이라면 useState로 관리해도 무방하다. 그러나, 컴포넌트에서 관리하는 값이 여러개이거나, 복잡한 구조로 되어있다면 useReducer로 관리하는 것이 편리할 수 있겠다.

0개의 댓글