본문 바로가기
  • 삽질하는 자의 블로그
React/React-Basic

4. useReducer 바로 알기 - 기본편

by 이게뭐당가 2022. 12. 8.

useReducer 는, 강력한 State 관리 도구이다.

 

useState 에 비해, 조금 복잡하지만, 많은 state의 변화를 가져오는 action (실행 함수)  을 한군데 모아,

가독성 있게 State 를 관리 할 수 있다.

 

또한,  컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다. 

 

useReducer는, 크게 두가지 파트가 있다.

리듀서 함수, 그리고 리듀서함수를 dispatch 하여 사용하기

 

1. 리듀서함수

   리듀서 함수는, type 이라는 action의 이름을 이용하여, 각 type 에 맞는, action을 취하게 한다.

   리듀서 함수의 반환값 (쉽게 말하면, 각각의 type에 맞는 action이 일어난 후 return 값) 은, 새로운 상태 를 반환한다.

 

     * 리듀서함수는 컴포넌트 함수 밖에서 정의할 수 도 있다(대부분 그렇다)

 

2. 리듀서함수의 dispatch

    각 type 에 맞는 action을, 리듀서 함수에 정의했다면,

    컴포넌트 함수 내부에서, dispatch 를 통해, type 프로퍼티 에 접근하여, 그 action을 가져올 수 있다.

    액션이 실행되면, 리듀서함수에서 정의한 action의 return ( 사실 리듀서 함수의 return ) 을 새 상태로 가져온다.

 

3. 기본 정의

   

   자세히 알아보자

    [기본]
    
        < 1. 리듀서함수의 정의 >

            function reducerFn(state, action){          => 리듀서함수는, "현재상태"와 "액션"을 파라미터로 받아와서 "새로운 상태를 반환해주는 함수"
                retrun nextState                        => 리듀서 함수의 반환값은 곧, "새로운 상태"
            }

                * state : 현재 상태
                * action : "type" 값이 존재하고, "나머지는 맘대로 무엇이든 넣을 수 있는", "객체형태"의 코드
                    type 은 보통, "대문자", "_" 를 사용한다.


                <리듀서 함수 예시> ============================================================

                    => "취할 모든 액션을 정의한다."

                    function reducer(state, action) {           // 무엇이든, "action.type"을 확인하여, "원하는 action"을 취하게한다.
                        if (action.type == "INCREMENT") {      
                            return state + 1;                    // 반환에는, "state" 를 변화시킨다.
                        }    
                        if(action.type == "DECREMENT")  {
                            return state - 1;
                        }   
                    }

        << 2. 컴포넌트 함수 내에서, 정의한 "리듀서함수"를 가져와서 사용하기 >>

                function Counter(){
                    const  [number, dispatch] = useReducer(reducerFn, 0);

                    function OnIncrease(){
                        dispatch({type: 'INCREMENT' })
                    }

                    function OnDecrease(){
                        dispatch({type: 'DECREMENT' })
                    }

                    retrun (
                        <div>
                            <button onClick={OnIncrease}> +1 </button>
                            <button onClick={OnDecrease}> -1 </button>
                        </div>
                    )
                }

        << 3. 결합 >>

                import React, { useReducer } from 'react';

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

                function Counter() {
                    const [number, dispatch] = useReducer(reducer, 0);

                    const onIncrease = () => {
                        dispatch({ type: 'INCREMENT' });
                    };

                    const onDecrease = () => {
                        dispatch({ type: 'DECREMENT' });
                    };

                    return (
                        <div>
                            <h1>{number}</h1>
                            <button onClick={onIncrease}>+1</button>
                            <button onClick={onDecrease}>-1</button>
                        </div>
                    );
                }

                export default Counter;

 

   [결론]
 
1. useReducer는 리듀서함수, 초기값, 초기함수 를 파라미터로 갖는다

2. 리듀서함수는, state와, action 을 파라미터로 갖는다.

3. 리듀서함수는, "반환값으로" , "변할 State 를 갖는다"            [ useState 의 setValue() 처럼]

4. 리듀서함수는, "실행 될 action"을 "전부 적고", "type" 에 따라, "다른 action을 취하도록 한다".

5. 리듀서함수의 action(실행함수) 를 사용하기 위해, "dispatch" 명령어로,
                                      "action 안에 정의한 객체 프로퍼티 type 을 가져온다."   [type == id(불러올때 쓸 이름)]

6. "dispatch"로 "특정 type을 정하여", [리듀서 함수의 action(실행함수)를 불러오는 것]이다.

7.  "action 이 실행"되면, "type(action)마다 정해진, 다른 return 값" 이, "새로운 상태"가 된다.

 

추가적으로, 대부분의 Reducer 의 State 는 객체 값을 가진다.

 

import { useReducer } from "react";

function reducerFn(state, action) {
  if (action.type == "GET_INFO") {
    return { name: "ms", age: 35 };         // "객체값을 갖을 수 있다."
  }
  if (action.type == "DELETE_INFO") {
    return { name: null, age: null };
  }
}

function GetUserInfo() {
  const [userInfo, dispatch] = useReducer(reducerFn, { name: "", age: null });

  function getInfo() {
    dispatch({ type: "GET_INFO" });
  }
  function deleteInfo() {
    dispatch({ type: "DELETE_INFO" });
  }
  console.log(userInfo);
  return (
    <div>
      <button onClick={getInfo}> 얻기 </button>
      <button onClick={deleteInfo}> 지우기 </button>
    </div>
  );
}

export default GetUserInfo;

4. 페이로드 활용하기

 

 페이로드를 활용하면, dispath를 진행하여, action을 가져올때, action 객체에, 프로퍼티 값을 넣을 수 있다.

function userInfoReducer(state, action) {
  if (action.type == "GET_INFO") {
    return { name: "ms", age: 35, address: action.address }; // "페이로드로, action객체에 값을 넣는다.."
  }
  if (action.type == "DELETE_INFO") {
    return { name: null, age: null };
  }
}

function GetUserInfo() {
  const [userInfo, dispatch] = useReducer(userInfoReducer, {
    name: "",
    age: null,
  });

  function getInfo() {
    dispatch({ type: "GET_INFO", address: "busan" });	// 페이로드로 action 객체에 값을 넣는다.
  }
  ...
  
  console.log //  { name: "ms", age: 35, address: "busan" }

5. useEffect의 종속성을, state Object 로 사용할때, 문제점과 해결 (destructuring)

 

 state Object를 useEffect 의 종속성에 그대로 넣으면, state 의 모든 프로퍼티가 하나라도 변경 될 때마다 실행 되는

 

너무나 많이 실행되는 useEffect를 볼 수 있다.

 

이것은 좋지 않다.

 

destructuring을 통해, Object 가 아닌, Property 로 종속성을 변경하자

 

function GetUserInfo() {
  const [userInfo, dispatch] = useReducer(userInfoReducer, {
    name: "",
    age: null,
  });
  
  일때,
  
  useEffect(()=>{
  	...
  },[ userInfo ]) 	// 이렇게 사용하지 않는다.
  
  
  <개선> 
  
  useEffect(()=>{
  	...
  },[ userInfo.name ]) 	// 프로퍼티를 뽑아 사용한다.

 

 

 

댓글