[React] Hooks 의 규칙

SuamKang·2023년 7월 11일
0

React

목록 보기
20/34
post-thumbnail

Rules of Hooks


리엑트 훅은
함수형 컴포넌트로 로직을 구성할때 좀 더 상태를 관리하기 편하고 유용하게 대처하기 위해서 리액트에서 제공하는 기능이다.

useState, useEffect, useReducer,useContext 등등 더 많은 기능이 탑재된 훅들이 존재한다.

이러한 훅들은 사용하는 규칙이 있고 이는 매우 중요하다.
리액트 훅은 단순히 "use"로 시작하는 모든 함수이다.

1. 리액트 컴포넌트 함수에서만 호출(import)해야 한다.


리액트 컴포넌트 함수 혹은 사용자 정의 훅(custom hooks)에서 호출 가능하다.

예를 들면

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

import Card from "../UI/Card/Card";
import classes from "./Login.module.css";
import Button from "../UI/Button/Button";
import AuthContext from "../../store/auth-context";

// 이메일 리듀서
const emailReducer = (state, action) => {
  if (action.type === "USER_INPUT") {
    return { value: action.payload, isValid: action.payload.includes("@") };
  }
  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.payload, isValid: action.payload.trim().length > 6 };
  }
  if (action.type === "INPUT_BLUR") {
    return { value: state.value, isValid: state.value.trim().lenth > 6 };
  }

  return { value: "", isValid: false };
};

const Login = (props) => {
  const [formIsValid, setFormIsValid] = useState(false);
  const [email, emailDispatch] = useReducer(emailReducer, {
    value: "",
    isValid: null,
  });
  const [password, passwordDispatch] = useReducer(passwordReducer, {
    value: "",
    isValid: null,
  });

  const authCtx = useContext(AuthContext);

  const { isValid: isValidEmail } = email;
  const { isValid: isValidPassWord } = password;

  useEffect(() => {
    const identifier = setTimeout(() => {
      console.log("useEffect안 사이드이펙트 로직 실행");
      setFormIsValid(isValidEmail && isValidPassWord);
    }, 1000);

    return () => {
      console.log("이전 로직 초기화");
      clearTimeout(identifier);
    };
  }, [isValidEmail, isValidPassWord]);

  // 이메일 입력 함수
  const emailChangeHandler = (event) => {
    emailDispatch({ type: "USER_INPUT", payload: event.target.value });
  };

  // 비번 입력 함수
  const passwordChangeHandler = (event) => {
    passwordDispatch({ type: "USER_INPUT", payload: event.target.value });
  };

  // 이메일 스타일 유효성 함수
  const validateEmailHandler = () => {
    emailDispatch({ type: "INPUT_BLUR" });
  };

  // 비번 스타일 유효성 함수
  const validatePasswordHandler = () => {
    passwordDispatch({ type: "INPUT_BLUR" });
  };

  // 새로운 폼 전달 함수
  const submitHandler = (event) => {
    event.preventDefault();
    authCtx.onLogin(email.value, password.value);
  };

  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <div
          className={`${classes.control} ${
            email.isValid === false ? classes.invalid : ""
          }`}
        >
          <label htmlFor="email">E-Mail</label>
          <input
            type="email"
            id="email"
            value={email.value}
            onChange={emailChangeHandler}
            onBlur={validateEmailHandler}
          />
        </div>
        <div
          className={`${classes.control} ${
            password.isValid === false ? classes.invalid : ""
          }`}
        >
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            value={password.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;

Login.js에서 사용하는 Login 컴포넌트는 컴포넌트 함수이다. 왜냐하면 jsx를 리턴해 주기때문이다.

하지만, emailRedcuer 함수는 jsx를 반환하지않고, 객체를 반환한다.
그렇기 때문에 리액트 컴포넌트가 아니다.
이 안에선 useState를 호출할 수 없다.


2. 오직 최상위 level에서만 호출해야한다.


리액트 컴포넌트 함수 or 사용자 정의 훅 함수의 최상위 수준에서만 import가능하다.

중첩함수 또는 block문(if문 등)에선 호출하면 안된다.

만약 마찬가지로 Login컴포넌트 함수 내부에서 사용되고 있는 useEffect 함수내에서 useState 나 useContext등 훅을 사용하면 안된다. 오류가 난다.

이렇게 2가지가 공식적인 규칙이라면,
한가지 추가해서 알아 둘 필요가 있는게 있다.

바로 useEffect 훅이다.

useEffect는 항상 참조하는 모든 항목들을 의존성으로 useEffect 내부에 추가해야한다!

useEffect 내부에서 의존되는 항목들중 브라우저가 제공하는 API는 의존성을 추가할 필요는 없고, 브라우저에서 오지 않거나 컴포넌트 함수 외부에서 오는 데이터들은 useEffect함수 내부에서 의존성 배열로 추가 해주어야한다.

이렇게해서 3가지 정도의 규칙을 인지하고 리액트 앱을 구성해 나가면 오류나 더 나은 컴포넌트를 구현 할 수 있을것 같다.

profile
마라토너같은 개발자가 되어보자

0개의 댓글