그럼에도 불구하고

👨‍💻

[React] useReducer란? 본문

React/React basics

[React] useReducer란?

zenghyun 2023. 4. 8. 09:32

오늘은 useReducer에 대해 알아보겠습니다. 

 

[ useReducer ] 

React 공식 문서에 따르면 useReducer는 useState의 대체 함수라고 합니다.

 

위와 같이 React 공식 문서에서 언급된 것처럼, useReducer는 State(상태)를 관리하고 업데이트하는 Hook에만 useState를 대체할 수 있는 Hook 훅입니다. 다시 말해, useReducer는 useState처럼 State를 관리하고 업데이트할 수 있는 Hook입니다. 

 

useReducer의 묘미는, 한 컴포넌트 내에서 State를 업데이트하는 로직 부분을 그 컴포넌트로부터 분리시키는 것을 가능하게 해 준다는 것입니다.

 

그렇게 useReducer는 State 업데이트 로직을 분리하여 컴포넌트의 외부에 작성하는 것을 가능하게 함으로써, 코드의 최적화를 이루게 해 줍니다. 

 

[ useState vs useReducer ] 

💡 useState :

useState는 React 컴포넌트에서 상태(state)를 다루는 Hook입니다.

컴포넌트에서 상태를 변경하면, 해당 컴포넌트가 다시 렌더링 됩니다.

상태가 변경되면, 컴포넌트가 화면에 다시 그려져서 새로운 상태가 반영됩니다.

 

useState는 다음과 같은 상황에서 사용합니다.

 

- 컴포넌트 내부에서 변경 가능한 상태를 다룰 때

- 사용자의 입력에 따라 컴포넌트가 동적으로 변경되어야 할 때

- 상태를 초기화하거나 업데이트할 때

 

💡 useReducer : 

useReducer는 React 컴포넌트에서 상태(state)를 다루는 또 다른 Hook입니다.

useReducer는 useState와 비슷하게 상태를 변경할 수 있지만, 좀 더 복잡한 로직을 다룰 수 있습니다.

useReducer는 상태와 액션(action)을 받아서, 새로운 상태를 반환하는 리듀서 함수를 이용합니다.

 

useReducer는 다음과 같은 상황에서 사용합니다.

 

- 복잡한 상태 로직을 다룰 때

- 여러 개의 연관된 상태를 함께 다룰 때

- 컴포넌트의 상태 업데이트 로직을 다른 파일로 분리하고 싶을 때

 

 

💡 useState vs useReducer :

- useState는 간단한 상태 로직을 다루기에 적합합니다.

- useReducer는 좀 더 복잡한 상태 로직을 다룰 수 있습니다.

- useState는 상태를 업데이트할 때 이전 상태를 덮어쓰는 반면, useReducer는 이전 상태를 변경하지 않고, 새로운 상태를 생성합니다.

- useState는 한 개의 상태만 다룰 수 있지만, useReducer는 여러 개의 연관된 상태를 함께 다룰 수 있습니다.

- useState 컴포넌트 내부에서 상태를 다루지만, useReducer 다른 파일에서 리듀서 함수를 정의하여 상태를 다룰 있습니다.

 

요약하자면,

 

📌  useState 

- 관리해야 할 State가 1개일 경우

- 그  State가 단순한 숫자, 문자열 또는 Boolean 값일 경우 

 

 

📌  useReducer

 - 관리해야 할 State가 1개 이상, 복수일 경우

 - 혹은 현재는 단일 State 값만 관리하지만, 추후 유동적인 가능성이 있는 경우

 - 스케일이 큰 프로젝트의 경우

 - State의 구조가 복잡해질 것으로 보이는 경우 

 

[ useReducer 기본 코드 구조

전체 샘플 코드

React 튜토리얼에서 흔히 볼 수 있는 Counter 앱입니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, { useReducer } from "react";
 
function reducer(state, action) {
  switch (action.type) {
    case "decrement":
      // action의 type이 "decrement"일 때, 현재 state 객체의 count에서 1을 뺀 값을 반환함
      return { count: state.count - 1 };
    case "increment":
      // action의 type이 "increment"일 때, 현재 state 객체의 count에서 1을 더한 값을 반환함
      return { count: state.count + 1 };
    default:
      // 정의되지 않은 action type이 넘어왔을 때는 에러를 발생시킴
      throw new Error("Unsupported action type:", action.type);
  }
}
 
function Counter() {
  const [number, dispatch] = useReducer(reducer, { count: 0 });
 
  return (
    <>
      {/* 현재 카운트 값은 state인 number 객체의 count로부터 읽어옴 */}
      <h1>Count: {number.count}</h1>
      {/* 카운트 값의 변경을 위해 각 버튼이 클릭되면 dispatch 함수가 발동되면서 reducer 함수가 실행됨.
          dispatch 함수의 인자로, action 객체가 설정되었는데,
          action 객체의 type에는 어떤 버튼을 클릭하였는지에 따라
          "decrement" 또는 "increment"가 들어감
      */}
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
    </>
  );
}
 
export default Counter;
cs

 

useReducer를 사용하기 위한 구성 요소로는 크게 4가지가 있습니다.

 

1. useReducer 함수

2. action

3. dispatch 함수

4. reducer 함수 

 

 

📌   useReducer 함수 

 

useReducer 함수는 첫 번째 인자인 reducer 함수가 반환 (return) 하는 값으로 state를 갱신하는 역할을 합니다.

 

기본적으로 useReducer는 다음과 같은 형태로 사용됩니다. 

 

1
2
const [state, dispatch] = useReducer(reducer, initialState, init);
 
cs

 

🧷  state : 컴포넌트에서 사용할 State(상태)

 

🧷  dispatch : reducer 함수를 실행시키며, 컴포넌트 내에서 state의 업데이트를 일으키기 위해서 사용하는 함수 

 

🧷  reducer : 컴포넌트 외부에서 state를 업데이트하는 로직을 담당하는 함수. 현재의 state와 action 객체를 인자로 받아서, 기존의 state를 대체(replace)할 새로운 State를 반환 (return)하는 함수. 

 

🧷  initialState : 초기 State

 

🧷  init : 초기 함수

 

 

 

📌   action 

 

action은 업데이트를 위한 정보를 가지고 있는 것이며, dispatch의 인자가 되며, reducer 함수의 두 번째 인자인 action에 할당됩니다.

action은 따로 정해진 형태는 없으나 아래의 코드와 같이 주로 type라는 값을 지닌 객체 형태로 사용된다고 합니다. 

 

우리의 샘플 코드를 예로 들면, { type: "decrement" } 이 부분이 action입니다.

 

1
dispatch({ type: "decrement" })
cs

 

 

 

📌   dispatch 함수 

 

dispatch 함수는 reducer 함수를 실행시킵니다.

dispatch 함수의 인자로써 업데이트를 위한 정보를 가진 action를 이용하며, 컴포넌트 내에서 state의 업데이트를 일으키기 위해 사용됩니다.

 

dispatch 함수의 인자인 action은 reducer 함수의 두 번째 인자인 action에 할당됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Counter() {
  const [number, dispatch] = useReducer(reducer, { count: 0 });
 
  return (
    <>
      {/* 현재 카운트 값은 state인 number 객체의 count로부터 읽어옴 */}
      <h1>Count: {number.count}</h1>
      {/* 카운트 값의 변경을 위해 각 버튼이 클릭되면 dispatch 함수가 발동되면서 reducer 함수가 실행됨.
          dispatch 함수의 인자로, action 객체가 설정되었는데,
          action 객체의 type에는 어떤 버튼을 클릭하였는지에 따라
          "decrement" 또는 "increment"가 들어감
      */}
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
    </>
  );
}
cs

 

 

 

📌   reducer 함수 

 

reducer 함수는 dispatch 함수에 의해 실행되며, 컴포넌트 외부에서 state를 업데이트하는 로직을 담당합니다.

 

useReducer 함수의 첫 번째 파라미터로 입력된 reducer 함수는, 현재의 state와 action은 인자로 받게 되는데,  이 action 값에 근거하여 기존의 state를 대체(replace)할 새로운  state를 반환(return) 합니다. 

 

아래 reducer 함수의 코드에서는, 간편하게 switch문을 이용하여 action의 값이 무엇인지에 따라 새로운 state를 반환(return) 하고 있습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
  }
}
cs

 

reducer 함수에서 짚고 넘어가야 할 점은, 

기존의 state를 새로운 state로 대체(replace)한다는 것입니다.

기존의 state를 변경하거나, 추가하거나, 덮어쓰지 않는다는 것 입니다.

'React > React basics' 카테고리의 다른 글

[React] useMemo와 useCallback 이란?  (0) 2023.04.14
[React] Context API란?  (0) 2023.04.10
[React] useEffect란?  (0) 2023.04.07
[React] useRef란?  (0) 2023.04.06
[React] Portal이란?  (0) 2023.04.06
Comments