[React] useReducer()

2023. 1. 27. 16:04·FE·Client/React
728x90

* useReducer()

useState의 대체 함수로, (state, action) => newState의 형태로 reducer를 받고 

dispatch 메서드와 짝의 형태로 현재 state를 반환한다.

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.reactjs.org

useReducer는 내장된 훅으로 state관리를 도와준다.(=useState와 기능이 유사하지만, 더 많은 기능이 있음)
그래서 더 복잡한 state에 특히 유용하다.

 

여러 state들이 함께 속해 있는 경우 (복잡한 state) - 여러 state가 함께 바뀌거나, 서로 관련되어 있는 경우

useState나 거기에서 얻은 state는 사용 및 관리가 어려워지거나 오류가 발생하기 쉽다.

더 강력한 useState를 사용하고 싶다면 useReducer를 대신해서 사용할 수있다.

더 강력하다 != 더 좋다, 꼭 필요한 곳에서만 사용하고 대부분의 경우에는 useState를 사용

 

함께 속하는 state들이 있는 경우 useReducer를 사용하기 딱 좋다.

 1) 입력된 값이 있고 - 그 값의 유효성이 있는 경우

 2) 다른 state에 의존하여 state를 업데이트하는 경우

1과 2가 함께하는 경우에 하나의 state 내에서 객체로 관리하면 useReducer를 사용하지 않아도 괜찮다.

다만, 객체가 값과 유효성 두가지가 아니라 더 복잡한 state들의 집합체라면 useReducer를 사용하는 것을 권장.

 

const [state, dispatchFn] = useReducer(reducerFn, initialState, initFn);

useReducer는 useState처럼 항상 두개의 값이 있는 배열을 반환한다.

 1) state: 최신 state 스냅샷

 2) dispatchFn: state 스냅샷을 업데이트 해줄 수 있는 함수(새로운 state값을 설정하는 대신 액션을 dispatch한다.)

 3) reducerFn(리듀서함수): dispatchFn에서 dispatch된 액션은 useReducer의 첫번째 인수인 reducerFn이 소비한다. 즉, 최신 state 스냅샷을 자동으로 가져오는 함수. 또한, 새로 업데이트된 state를 반환한다.(useState의 함수와 비슷)

(리액트는 새 액션이 dispatch될 때 마다 리듀서 함수를 호출한다. > 리액트가 관리하는 최신의 state 스냅샷을 가져온다. > 리듀서 함수를 실행시키는 dispatch된 액션을 가져온다.)

 4) initialState: 초기 state

 5) initFn: 초기 함수

 

useReducer는 useState와 함께 사용해주면 더 유효한 효과를 낼 수 있다.

//컴포넌트 바깥에 Reducer함수를 선언했는데, 이는 리듀서 함수 내부에서는 컴포넌트 함수 내에서 만들어진 어떤 데이터도 필요하지 않기 때문이다.
//컴포넌트 내에 만들어진 어떤 데이터와도 상호작용하지 않기 때문에 컴포넌트 바깥에서 선언해도 괜찮다.
//action으로 디스패치하는 것은 객체이다.
const emailReducer = (state, action) => {
  if(action.type === 'USER_INPUT'){
    return {value:action.val, isValid:action.val.includes('@')};
  }
  //최신 값을 가져오기 위해서는 state.value사용하면 된다.
  if(action.type === 'INPUT_BLUR'){
    return {value:state.value, isValid:state.value.includes('@')};
  }

  //비어있는 스냅샷
  return {value:'', isValid: false};
};

const passwordReducer = (state, action) => {
  if(action.type === 'USER_INPUT'){
    return {value: action.val, isValid:action.val.trim().length>6 }
  }
  if(action.type === 'INPUT_BLUR'){
    return {value: state.value, isValid:state.value.trim().length>6}
  }
  return {value:'', isValid:false};
}
const [emailState, dispatchEmail ] = useReducer(emailReducer,{
    value: '',
    isValid: undefined,//또는 null로 설정하면 invalid로 처리되지 않는다.
  });

  const [passwordState, dispatchPassword] = useReducer(passwordReducer, {
    value: '',
    isValid: undefined,
  })
//객체 디스트럭처링 구문(별칭할당)
  const { isValid:emailIsValid } = emailState;
  const { isValid:passwordIsValid} = passwordState;
  
  useEffect(()=>{
    //setTimeout함수를 사용하는 이유는, 입력이 들어올 때 마다 상태를 업데이트 해주기 때문에
    //이를 방지하기 위해 사용자의 입력이 일정시간 없을 때, 유효한지를 검사해주기 위함임.
    const identifier = setTimeout(()=>{
      console.log('Checking from validity!');
      setFormIsValid(
        emailIsValid && passwordIsValid
      );
    },500);

    //useEffect가 다음 번에 함수를 실행하기 전에 클린업 프로세스로 실행된다.
    // 모든 사이드이펙트 함수가 실행되기 전, 컴포넌트가 제거되기 전,
    return () => { 
      console.log('CLEANUP');
      //새로운 타이머를 설정하기 전 마지막 타이어를 지우는 clearTimeout 
      clearTimeout(identifier);
    };
  },[emailIsValid, passwordIsValid]);

객체 디스트럭처링을 사용해 isValid를 불러오기 위한 변수명을 지정해준다.

매번 타이핑 될 때마다 유효성 검사를 하는 것은 불필요하기 때문에, 유효한 경우에는 유효성 검사를 하지 않게 하려고 한다.

이 경우 state가 바뀔때 마다 검사를 하게 되니, 디스트럭처링을 사용해 유효한지 확인하는 경우에만 useEffect가 실행되게 한다면, 더욱 효과적.

 


* useState() vs useReducer()

useState를 사용하면 너무 번거로운 경우 useReducer를 사용한다.(너무 많은 일들을 처리해야 하는 경우)

관련 state 스냅샷들이 서로 독립적이고 같이 업데이트가 안된다면 useReducer사용

 

useState

- state관리 툴

- 개별 state 및 데이터 다루기 적합

- 간단한 state에 적합

- state가 몇 종류 안될 때

- state로서의 객체가 존재하지 않을 때

ex) 두 개의 서로 다른 값을 전환하기만 하는 단순한 state가 있는 경우

 

useReducer

- state로서의 객체가 존재할 때, 혹은 복잡한 state를 보유하고 있을 때 리듀서함수 사용(컴포넌트 바깥에 정의 가능)

- 연관된 state조각들로 구성된 관련 데이터를 다루는 경우(ex. 폼 input state가 있는 경우)

- 더 복잡한 state가 존재한 경우나, state하나를 변경하는 여러 다른 액션이 존재할 경우

728x90

'FE·Client > React' 카테고리의 다른 글

React Hook 규칙, Forward Refs, useImperativeHandle(focus와 scroll)  (0) 2023.01.29
[React] sh: react-scripts: command not found에러  (0) 2023.01.29
[React] sideEffect() 와 useEffect()  (0) 2023.01.17
[React] Portals, Ref, uncontrolled component  (0) 2023.01.11
[React] 리액트 컴포넌트 스타일링, styled-components, 미디어쿼리, CSS 모듈  (0) 2023.01.09
'FE·Client/React' 카테고리의 다른 글
  • React Hook 규칙, Forward Refs, useImperativeHandle(focus와 scroll)
  • [React] sh: react-scripts: command not found에러
  • [React] sideEffect() 와 useEffect()
  • [React] Portals, Ref, uncontrolled component
DROPDEW
DROPDEW
💻 Developer | 기록하지 않으면 존재하지 않는다
  • DROPDEW
    제 2장 1막
    DROPDEW
  • 전체
    오늘
    어제
    • categories (401) N
      • App/Android (1)
      • BE (36) N
        • HTTP 웹 기본 지식 (8)
        • 스프링 입문 - 코드로 배우는 스프링 부트, 웹 .. (12)
        • 스프링부트와 JPA 활용 (3) N
        • 스프링부트 시큐리티 & JWT (0)
        • PHP (6)
      • FE·Client (23)
        • HTML (1)
        • React (19)
        • Unity (1)
      • Data (12)
        • AI (4)
        • Bigdata (6)
        • Database (1)
        • 빅데이터분석기사 (0)
      • Infra (0)
      • CS (7)
        • CS 면접 준비 (3)
      • 취준 (13)
        • 자격증·인턴·교육 (4)
        • 인적성·NCS (6)
        • 코테·필기·면접 후기 (3)
      • 코테 (268)
        • Algorithm (220)
        • SQL (35)
        • 정리 (13)
      • 인사이트 (27)
        • 금융경제뉴스 (7)
        • 금융용어·지식 (2)
        • 북마크 (7)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    브루트포스 알고리즘
    오블완
    최단경로
    그리디알고리즘
    구현
    너비우선탐색
    투포인터
    이분탐색
    문자열
    다이나믹프로그래밍
    시뮬레이션
    누적합
    수학
    백준
    티스토리챌린지
    자료구조
    그래프탐색
    매개변수탐색
    정렬
    그래프이론
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
DROPDEW
[React] useReducer()
상단으로

티스토리툴바