React Hooks - useReducer

박정호·2022년 8월 30일
0

React Hook

목록 보기
7/12
post-thumbnail
post-custom-banner

🪝 useReducer

  • useReducer는 useState처럼 state를 관리하고 업데이트 할 수 있는 Hook
  • 컴포넌트의 외부에 작성하는 것을 가능하게 하여, 코드를 최적화 시켜준다
  • 상태관리를 위한 reducer function에 접근할 수 있게 한다
  • useState의 대체 함수이다.(공식문서)

✏️ useState를 사용하는 경우

  • 컴포넌트 내부에 State업데이트 로직이 존재하는 것을 확인 가능

✏️ useReducer를 사용하는 경우

  • 컴포넌트 외부에 State 업데이트 로직이 분리되어 있는 것을 확인 가능

🧐 사용 이유?

State을 변경하고 관리하는 것은 useSate으로도 가능한데 useReducer를 사용하는 이유는 무엇일까?

useState VS useReducer

✏️ useState의 경우, 관리해야할 State가 적고 단순한 숫자,문자열, boolean값일 경우 사용하는 것이 좋다.

✏️ useReducer의 경우, 관리해야할 State가 많고 구조가 복잡한 규모가 다소 큰 프로젝트에서 사용하는 것이 좋고 유지보수가 좋다.

⭐️ 구성 요소

useReducer 구조

  • reducer: 컴포넌트 외부에서 state를 업데이트하는 로직을 담당하는 함수
  • initialState: 초기 State
  • init: 초기 함수
const [state, dispatch] = useReducer(reducer, initialState, init);

useReducer는 총 4가지로 구성된다.

1️⃣ useReducer

첫번째 인자인 reducer가 return하는 값으로 state(상태)를 갱신하는 역할

설명) reducer가 반환한 새로운 값을 number라는 state에 갱신한다. 그 이전까지의 number의 값은 0으로 초기값을 설정한다.

  const [number, dispatch] = useReducer(reducer, { count: 0 });

2️⃣ action

업데이트해야할 정보를 가지고 있는 것으로, dispatch의 인자에 담긴다.
쉽게 말해, reducer가 무엇을 해야할지 담겨있는 명령어 이다.

설명) action은 대부분 type이라는 값에 객체 형태로 담긴다. decrement,increment라는 명령어가 dispatch의 인자로 담겨있는 것이다.

 <button onClick={() => dispatch({ type: "decrement" })}>-</button>
 <button onClick={() => dispatch({ type: "increment" })}>+</button>

3️⃣ dispatch

reducer함수를 실행시킨다. dispatch의 인자로 action을 담아서 업데이트를 일으키기 위해서 사용된다.
쉽게 말해 ruducer에게 action이라는 명령어를 주는 명령자 역할이다.

설명) 버튼 클릭시 dispatch함수가 실행되어 action을 인자에 담고 reducer에 업데이트를 요청한다.

 <button onClick={() => dispatch({ type: "decrement" })}>-</button>
 <button onClick={() => dispatch({ type: "increment" })}>+</button>

4️⃣ reducer

dispatch에 의해 실행되는 함수로, 외부에서 state을 업데이터히는 로직을 담당하는 함수이다. action의 값에 따라서 기존의 state값을 새롭게 return한다.
쉽게 말해, dispatch의 action 명령에 따라서 state값을 변경하는 역할을 한다.

설명) reducer함수 내부의 switch문에서는 action의 값에 따라 발생할 case가 결정된다. 결정된 case안에서 기존의 state값이 새로운 값으로 변경되어 return되어지는 과정이다.

function reducer(state, action) {
  switch (action.type) {
    case "decrement":
      // action의 type이 "decrement"일 때, 현재 state에서 1을 뺀 값을 반환함
      return state - 1;
    case "increment":
      // action의 type이 "increment"일 때, 현재 state에서 1을 더한 값을 반환함
      return state + 1;
    default:
      // 정의되지 않은 action type이 넘어왔을 때는 에러를 발생시킴
      throw new Error("Unsupported action type:", action.type);
  }
}

예시 출처: React Hooks :: useReducer에 대해 알아보기

💡중요) reducer는 새로운 state값을 만든다.

reducer는 기존의 state를 수정(modify)하거나, 추가(add)하거나, 덮어쓰지(overwrite) 하지 않고, 기존의 state를 새로운 state로 (대체)replace한다.

쉽게 말해,기존의 state를 바로 수정하지 않고 복사한 뒤에 복사한 값을 수정하여 새로운 값으로 변경하면 된다.

⭐️ 복사를 할때는 얕은 복사(Shallow Copy) 깊은 복사(Deep Copy)가 있다.

✏️ 얕은 복사는 참조(주소)값의 복사를 의미한다.

const obj = { value: 10 }
const newObj = obj

newObj.value = 5;

console.log(obj.value); // 5
console.log(newObj.value); // 5

위와 같이 obj를 newObj에 참조할당할 경우, newObj의 값을 변경하면 obj 또한 같은 주소값을 공유하기 때문에 데이터가 함께 변경된다.
이처럼 reducer에서 만약 얕은 복사로 기존의 state값을 변경하면 값이 변경되어서 기존의 state값을 사용하던 다른 컴포넌트에서 에러가 발생할 수 있게 된다.

따라서 reducer에서는 깊은 복사를 꼭 사용하도록 하자!

✏️ 깊은 복사는 값 자체를 복사하여 다른 주소값을 지닌다.

JS의 원시타입은 깊은 복사가 가능하며, 이는 독립적인 메모리에 값 자체를 새롭게 할당하여 생성하는 것이다. 많이 사용되는 깊은 복사는 Object.assign()와 spread연산자가 있다.

const obj = { value: 10 }
const newObj = { ...obj }

newObj.value = 5

console.log(obj.value); // 10
console.log(newObj.value); // 5

👍 정리

✏️ 장점

  • useState, setState를 여려번 사용하지 않아도 된다.
  • 로직이 분리되어 있어서 다른 곳에서도 쉽게 재사용이 가능하다
  • 서로 같이 사용되는 변수들끼리 묶어주며 관리하기가 수월하다

✏️ 단점

  • useState의 사용보다 코드의 양이 많아진다
  • 비동기 로직과 함께 사용하는 방법이 제공되지 않는다.

✏️ 주의

  • 기존의 원본 State의 불변을 유지해야 한다.(깊은 복사를 사용하자!)


! 중요

reducer함수는 순수 함수로 작성하기 때문에, async함수가 될 수 없다. 따라서, redux를 사용하면 리덕스 미들웨어인 thunk, saga를 통해 비동기 처리가 가능하다.

✏️ 순수 useReducer의 비동기 처리
이벤트 발생 > 비동기 작업 > dispatch > 상태 변경(reducer) > 렌더링

✏️ 리덕스 미들웨어의 비동기 처리
dispatch > 비동기 작업 > 상태 변경 > 렌더링

useReducer와 ContextAPI를 통해 redux의 기능 대부분을 구현 가능하다. 하지만, 규모가 큰 프로젝트에서는 useReducer와 ContextAPI의 조합으로는 비동기적인 작업을 할시 불편하다.

💡 ContextAPI, useReducer, Redux에 대한 자세한 설명

Redux란?

ContextAPI + useReducer vs Redux

출처 및 참고하기 좋은 사이트

profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)
post-custom-banner

0개의 댓글