본문 바로가기
Study/Udemy-React-완벽 가이드

10.2 Reducer 사용하여 부작용 처리 & Context API 사용하기 : useReducer와 useEffect 함께 사용시 최적화 방법 (feat. 유데미 React 완벽 가이드)

by NFAP0221S 2022. 5. 31.

https://www.udemy.com/course/best-react/

 

【한글자막】 React 완벽 가이드 with Redux, Next.js, TypeScript

Javascript부터 웹 어플리케이션 배포까지, React와 프론트엔드 최신 기술을 가장 쉽고 확실하게 배우는 법

www.udemy.com

이 게시물은 유데미 React 완벽 가이드 강의를 보고 메모를 남기는 게시물 입니다.


구조분해할당으로 최적화하기

#1. useReducer와 useEffect를 함께 사용한 후 최적화를 하였다. 

어떻게 최적화 하였는지 #2 로 넘어가보자.

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

import Card from "../UI/Card/Card";
import classes from "./Login.module.css";
import Button from "../UI/Button/Button";

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

const passwordReducer = (state, action) => {
  if (action.type === "USER_INPUT") {
    return { value: action.val, isVaild: action.val.trim().length > 6 };
  }
  if (action.type === "INPUT_BLUR") {
    return { value: state.value, isVaild: state.value.trim().length > 6 };
  }
  return { value: "", isVaild: false };
};

const Login = (props) => {
  // const [enteredEmail, setEnteredEmail] = useState("");
  // const [emailIsValid, setEmailIsValid] = useState();
  // const [enteredPassword, setEnteredPassword] = useState("");
  // const [passwordIsValid, setPasswordIsValid] = useState();
  const [formIsValid, setFormIsValid] = useState(false);

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

  const [passwordState, dispatchPassword] = useReducer(passwordReducer, {
    value: "",
    isVaild: null,
  });

  useEffect(() => {
    console.log("EFFECT RUNNING");

    return () => {
      console.log("EFFECT CLEANUP");
    };
  }, []);
  // 구조분해할당으로 useReducer 와 useEffect를 함께 사용할때 최적화 방법
  const { isVaild: emailIsValid } = emailState;
  const { isVaild: passwordIsValid } = passwordState;

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

    return () => {
      console.log("CLEANUP");
      clearTimeout(identifier);
    };
  }, [emailIsValid, passwordIsValid]);

  const emailChangeHandler = (e) => {
    dispatchEmail({ type: "USER_INPUT", val: e.target.value });

    // setFormIsValid(e.target.value.includes("@") && passwordState.isVaild);
  };

  const passwordChangeHandler = (e) => {
    dispatchPassword({ type: "USER_INPUT", val: e.target.value });

    // setFormIsValid(emailState.isVaild && e.target.value.trim().length > 6);
  };
  // 이메일 유효성 검사
  const validateEmailHandler = () => {
    // setEmailIsValid(emailState.isVaild);
    dispatchEmail({ type: "INPUT_BLUR" });
  };
  // 비밀번호 유효성 검사
  const validatePasswordHandler = () => {
    // setPasswordIsValid(enteredPassword.trim().length > 6);
    dispatchEmail({ type: "INPUT_BLUR" });
  };

  const submitHandler = (event) => {
    event.preventDefault();
    props.onLogin(emailState.value, passwordState.value);
  };

  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <div
          className={`${classes.control} ${
            emailState.isVaild === false ? classes.invalid : ""
          }`}
        >
          <label htmlFor="email">E-Mail</label>
          <input
            type="email"
            id="email"
            value={emailState.value}
            onChange={emailChangeHandler}
            onBlur={validateEmailHandler}
          />
        </div>
        <div
          className={`${classes.control} ${
            passwordState.isValid === false ? classes.invalid : ""
          }`}
        >
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            value={passwordState.value}
            onChange={passwordChangeHandler}
            onBlur={validatePasswordHandler}
          />
        </div>
        <div className={classes.actions}>
          <Button type="submit" className={classes.btn} disabled={!formIsValid}>
            Login
          </Button>
        </div>
      </form>
    </Card>
  );
};

export default Login;

#2.  useReducer의 state로 emailState와 passwordState를 사용중이다. 

구조분해할당을 사용하여 최적화를 해보자.

  1.  객체를 만들어 프로퍼티를 isVaild로 하고 각각 state에 어울리는 값을 맵핑한다.
  2.  그리고 각각 state를 할당한다.
  3. state가 사용되어지는 곳에 프로퍼티의 값을 입력해주면 해당 값이 true일때만 emailState.isVaild 를 반환한다.
  // 구조분해할당으로 useReducer 와 useEffect를 함께 사용할때 최적화 방법
  const { isVaild: emailIsValid } = emailState;
  const { isVaild: passwordIsValid } = passwordState;

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

    return () => {
      console.log("CLEANUP");
      clearTimeout(identifier);
    };
  }, [emailIsValid, passwordIsValid]); // isVaild의 value

기존에는 유효성 검사를 통과해도 계속 콘솔 출력이 되었지만, 이 방법으로 최적화를 하면

유효성검사가 이루어져 true 일때만 useEffact의 의존성 배열이 업데이트 되기 때문에 불필요한 트래픽을 줄일 수 있다.