React hook의 모든 것(5) (useReducer)

신은수·2023년 6월 11일
0

ReactJS

목록 보기
7/13

1. useReducer란?

  • 상태를 관리할 때 useState 훅을 사용하여 관리 할 수 있음.
  • useState 훅을 사용하는것 말고도 다른 방법이 있는데 이는 바로 useReducer 훅.
  • useReducer훅은 복잡한 상태 관리가 필요할 때 주로 쓰임.

2. Redux 패턴 (reducer, dispatch, action)

  • reducer함수는 현재 state(상태)와 action(행동)객체를 인자로 받아 새로운 state를 반환하는 함수.
  • dispatch함수는 컴포넌트 내에서 상태 변경을 일으키기 위해서 사용되는데 인자로 action객체를 받음.
  • action객체는 어떤 부류의 행동인지를 나타내는 type 속성과 해당 행동과 괸련된 data를 담고 있음.
    -> dispatch함수에 action을 던지면, reducer함수가 이 행동(action)에 따라서 state를 변경해줌.
    -> 이렇게 텍스트로만 보면 이해가 쉽지는 않으니 직접 코드로 봐보자.

3. useReducer 코드로 이해하기

 import { useReducer } from "react";

 const reducer = (state, action) => {
   switch (action.type) {
     case "INCREASE":
       return state + 1;
     case "DECREASE":
       return state - 1;
     default:
       break;
   }
 };

 export default function Counter() {
   const [state, dispatch] = useReducer(reducer, 0);

   return (
     <div>
       <button
         onClick={() => {
           dispatch({ type: "INCREASE" });
         }}>
         +
       </button>

       {state}

       <button
         onClick={() => {
           dispatch({ type: "DECREASE" });
         }}>
         -
       </button>
     </div>
   );
 }

코드 설명

  • useReducer는 reducer함수와 초기 state를 인자로 받음. useReducer함수는 state와 dispatch함수를 반환.
  • +버튼을 누르면 dispatch함수에 action을 던지는 데 이 때 reducer함수가 작동하여 state를 변경.

-> 사실 이렇게 간단한 상태관리는 useState 훅을 쓰는 것이 더 좋을 수도 있음.
-> useReducer함수는 복잡한 상태관리를 할 때 빛을 발함.


4. useReducer를 통해 복잡한 상태관리

1) 코드를 통해 알아보자.

코드 설명 (출처: velopert님)

간단하게 기능에 대해 설명해보자면

  • 계정명과 이메일을 작성하고 등록버튼을 누르면 사용자를 등록할 수 있음.
  • 계정명을 클릭하면 활성 사용자로 등록하거나 해제할 수 있음.
  • 사용자 옆 삭제버튼을 누르면 사용자를 삭제할 수 있음.

2) useState로 상태관리하기

원래의 나라면 useState를 통해 두가지 상태로 분리하여 관리를 했을 것이다.

// 리액트 컴포넌트 안에서 정의
const [inputs, setInputs] = useState({username:"", email:""})
const [users, setUsers] = useState([])

const onCreate = () => {
  setUsers([...users, {...inputs, active: false}]);
  setInputs({ username: "", email: ""});
};                      

3) useReducer를 통해 상태관리하기

const initialState = {
  inputs: {
    username: '',
    email: ''
  },
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    }
};

function reducer(state, action) {
  switch (action.type) {
    case 'CREATE_USER':
      return {
        inputs: initialState.inputs,
        users: state.users.concat(action.user)
      };
    default:
      return state;
  }
}

///////////////////////////////////////////////////
 // 리액트 컴포넌트안에서 정의
const onCreate = () => {
  dispatch({
    type: 'CREATE_USER',
    user: {
      id: nextId.current,
      username,
      email
    }
  });
  nextId.current += 1;
}

-> state를 위에서 두 가지로 분리하지 않고, inputs과 users정보 모두 하나의 state로 관리하는 것을 볼 수 있다.

-> useReducer함수를 사용하면 컴포넌트의 상태 업데이트 로직(reducer함수)를 컴포넌트에서 분리시킬 수 있다. 상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 심지어 다른 파일에 작성 후 불러와서 사용 할 수도 있다.
(onCreate함수도 분리할 수 있지 않을까 생각했다. onCreate함수는 dispatch함수를 사용하고 있다. dispatch함수는 useReducer훅을 통해 반환되는데 리액트 훅의 경우 리액트 컴포넌트 안에서만 사용할 수 있기 때문에 분리가 불가능할 것 같다 -> custom hook을 쓴다면 가능할지도 모르겠다)


4) 언제 useReducer를 사용하나요?

  • 복잡한 상태관리에 useReducer를 사용하라는데 그 기준이 뭘까?
  • velopert님에 의하면
    setter를 한 함수에서 여러번 사용해야 하는 일이 발생한다면 그 때부터 useReducer를 쓸까?에 대한 고민을 시작한다고 함.
const onCreate = () => {
  setUsers([...users, {...inputs, active: false}]);
  setInputs({ username: "", email: ""});
};  
  • useReducer 를 썼을때 편해질 것 같으면 useReducer 를 쓰고, 딱히 그럴것같지 않으면 useState 를 유지하면 된다고....


정리

  • dispatch함수에 action을 던지면, reducer함수가 이 행동(action)에 따라서 state를 변경해줌.
  • 복잡한 상태관리를 해야할 때 useReducer 훅을 쓴다.
profile
🙌꿈꾸는 프론트엔드 개발자 신은수입니당🙌

0개의 댓글