본문 바로가기

공부기록/[강의노트] Udemy React 완벽가이드 101~200

# 125 [udemy React 완벽 가이드 노트] UseReducer 예시 (객체 디스트럭처링)

목표 :


login.js의 state를

큰 Form state 한개 또는 

작은 state 여러개로 관리해보자.

일단 배우기 위해서 emailState만 useReducer로 관리해보자.

( 값과 validity 를 하나의 state로 결합)

 

 

 

 

useReducer 작성해보기 


1. useReducer import하기

import React, { useState, useEffect, useReducer } from "react";

 

 

2. useReducer 디스트럭처링 작성

  const [emailState, dispatchEmail] = useReducer(emailReducer, );

 

 

3. emailReducer(앞에서 설명한 ReducerFn)을 Login 함수 바깥에 작성 

   (컴포넌트 내부에서 만들어진 데이터가 필요 없기 때문에)

   리듀서 함수 내부에서 요청되고 사용되는 모든 데이터는 

   이 함수로 전달 될 것임. 

 

 

const emailReducer = (state, action) => {}

 emailReducer는 state와 action을 매개변수로 받는데

최신 스냅샷과 디스패치 된 액션

 

 

  const [emailState, dispatchEmail] = useReducer(emailReducer, {
    value: "",
    isValid: false,
  });

useReducer의 두번째 인자는 initialState인데 

 emailState 스냅샷의 초기 형태이다. 

 

 

 

4. 코드 안에서 emailState를 사용해보자 

 

 

  const passwordChangeHandler = event => {
    setEnteredPassword(event.target.value);

    setFormIsValid(
      emailState.value.includes("@") && event.target.value.trim().length > 6
    );
  };

 

 

enteredEmail과 emailIsValid를 emailState. ???로 상황에 맞게 변경하자. 

 

예시 변경 전

 

 const validateEmailHandler = () => {
    setEmailIsValid(enteredEmail.includes("@"));
  };
  const emailChangeHandler = event => {
    setEnteredEmail(event.target.value);
  };
 const validateEmailHandler = () => {
    setEmailIsValid(enteredEmail.includes("@"));
  };

 

 

 

변경 후 

 const validateEmailHandler = () => {
    setEmailIsValid(emailState.isValid);
  };
const emailChangeHandler = event => {
    dispatchEmail({ type: "USER_INPUT", val: event.target.value });
    setFormIsValid(emailState.isValid && passwordState.isValid);
  };
const validateEmailHandler = () => {
    dispatchEmail({ type: "INPUT_BLUR" });
  };

 

 

emailReducer함수를 완성해보자

const emailReducer = (state, action) => {
  if (action.type === "USER_INPUT") {
    return { value: action.val, isValid: action.val.includes("@") };
  }

  if (action.type === "INPUT_BLUR") {
    return { value: state.value, isValid: state.value.includes("@") };
  }
  return { value: "", isValid: false };
};

 

그런데 이 코드가 최대한의 최적화는 아니다 

폼 valid 검사를 다른 state에서 도출하기 때문이다.  (passwordState.isValid)

 

 

 

 

그래서 useEffect를 함께 쓰기로 하자.


  useEffect(() => {
    const identifier = setTimeout(() => {
      console.log("Checking form validity!");
      setFormIsValid(emailState.isValid && passwordState.isValid);
    }, 500);

    return () => {
      clearTimeout(identifier);
    };
  }, [emailState, passwordState]);

 

여전히 state 스냅샷을 참조한다.

useEffect는 state가 변경되면 다시 실행된다. 

그래서 최신 state값으로 실행되게 된다. 

 

 

여기서 문제는


emailState와 passwordState가 변경될 때마다 계속 실행되어 너무 자주 실행 된다. 

dependencies를 isValid 부분으로 국한시켜보자. 

 

 

 

객체 디스트럭처링

 

배열 디스트럭처링과 비슷하지만 객체에서 한다. 

객체의 특정 속성을 추출함 

 

const { isValid: emailIsValid } = emailState;
const { isValid: passwordIsValid } = passwordState;

emailState에서는 isValid 속성을 추출할 수 있다. 

그리고 같은 이름의 새 상수(emailState)에 저장한다.

 

그리고 해당 속성을 추출하기 위해 별칭을 할당한다. (emailIsValid)

객체 디스트럭처링 구문의 일부이기 때문에, 

****값을 할당하는게 아니다****

 

{  } = ??? 을 쓰면 자동으로 되는 구문

 

이 별칭을 useEffect의 dependencies에 쓴다. 

 

  useEffect(() => {
    const identifier = setTimeout(() => {
      console.log("Checking form validity!");
      setFormIsValid(emailIsValid && passwordIsValid);
    }, 100);

    return () => {
      clearTimeout(identifier);
    };
  }, [emailIsValid, passwordIsValid]);

 

결과


값만 변경되고 해당 dependencies가 변경되지 않으면 

useEffect는 다시 실행되지 않는다. 

즉 객체 안의 속성이 변경될 때만 useEffect를 실행하고 싶으면 

위와 같은 방법을 사용하는 것이 좋다.