React

react-cookie

minsun309 2024. 9. 4. 09:04

키에 토큰(jwt)을 저장하거나 로그인 페이지 구성 시 id같은 사용자 정보를 저장하는 등 react-cookie 라이브러리를 활용하는 경우가 많 react-cookie에 대해 정리해보았다.

cookie?

쿠키는 사용자 웹 사이트 방문 시 생기는 4KB 이하의 작은 파일로 키와 값이 들어있는 데이터 파일 이다. 쿠키는 사용자가 페이지를 얼마나 자주 방문하는지 알려줌으로써, 사용자가 관심을 갖는 정보를 파악할 수 있도록 해주는 역할을 한다. 예를 들어 쇼핑몰 사이트의 장바구니를 상품을 넣고 며칠 후에 방문했을 때, 상품이 그래도 유지되어있는 이유는 쿠키를 활용하기 때문이다.

react-cookie

react-cookie npm

 

react-cookie

Universal cookies for React. Latest version: 7.2.0, last published: a month ago. Start using react-cookie in your project by running `npm i react-cookie`. There are 679 other projects in the npm registry using react-cookie.

www.npmjs.com

 

설치

npm install react-cookie
// or
yarn add react-cookie

 

기본 사용법

const [cookies, setCookie, removeCookie] = useCookies(['cookie-name']);
  • setCookie : 쿠키에 값 저장 | setCookie(쿠키 이름, 쿠키에 넣을 값, 옵션)
  • removeCookie : 쿠키 삭제 | removeCookie(쿠키 이름, 옵션)

⭐옵션 중 path는 쿠키 경로로 { path: "/" } 설정 시 모든 페이지에서 쿠키에 접근할 수 있다.

 

로그인 페이지 id 저장

react-cookie를 활용하여 사용자의 아이디를 기억 할 수 있게 구성했다.

 

계정 정보 저장

계정 정보 저장하기 <input type="checkbox" / > 를 클릭하면 onChange의 cookie값을 저장하거나 삭제하는 handleChangeRemember 함수가 실행된다.

const handleChangeRemember = (event: React.ChangeEvent<HTMLInputElement>) => {
    setRememberCheck(event.target.checked);

    if (event.target.checked) {
      setCookie("remember_id", getValues("email"), { path: "/" });
    } else {
      removeCookie("remember_id", { path: "/" });
    }
};

 

로그인 페이지 진입 시 쿠키 여부

만약 remember_id 이름의 쿠키가 존재한다면 <input type="checkbox" / > 의 checked를 true 로 변경하고 id 영역인 email의 값에 remember_id 값을 부여한다.

useEffect(() => {
    if (cookies.remember_id !== undefined) {
      setRememberCheck(true);
      setValue("email", cookies.remember_id);
    }
 }, []);

 

 

전체 코드

import { useCookies } from "react-cookie";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { useForm } from "react-hook-form";

export default function Login() {
  const router = useRouter();
  const [theme, setTheme] = useState("theme");

  useEffect(() => {
    const theme = localStorage.getItem("theme");
    setTheme(theme);
  }, []);

  const [passwordShow, setPasswordShow] = useState(false);
  const handlePasswordShow = () => {
    setPasswordShow((prev) => !prev);
  };

  const { register, handleSubmit, setError, watch, getValues, setValue, formState: { errors, isSubmitting }} = useForm<loginFormType>();

  // 계정정보 저장
  const [cookies, setCookie, removeCookie] = useCookies(["remember_id"]);
  const [rememberCheck, setRememberCheck] = useState<boolean>(false);

  useEffect(() => {
    if (cookies.remember_id !== undefined) {
      setRememberCheck(true);
      setValue("email", cookies.remember_id);
    }
  }, []);

  const handleChangeRemember = (event: React.ChangeEvent<HTMLInputElement>) => {
    setRememberCheck(event.target.checked);

    if (event.target.checked) {
      setCookie("remember_id", getValues("email"), { path: "/" });
    } else {
      removeCookie("remember_id", { path: "/" });
    }
  };

  const onValid = async (data: loginFormType) => {
    const result = await signIn("credentials", {
      redirect: false,
      email: data.email,
      password: data.password,
    });
    if (!result?.error) {
      router.replace("/");
    } else {
      setError("loginError", {
        message: "이메일 주소와 비밀번호를 다시 확인해주세요.",
      });
    }
  };

  const themeColor = theme === "light" ? "#121212" : "#dddddd";

  return (
    <div css={[loginPage]}>
      <div css={{color: themeColor}}>
        <div className="loginTop">
          <div className="logoArea"></div>
          <p className="loginTilte">
            PoledCS <span>관리자 로그인</span>
          </p>
        </div>
        <form onSubmit={handleSubmit(onValid)} css={loginForm}>
          <div className="input_area">
            <div>
              <div className="wIcon_area">
                <div className="left_icon">
                  <FiUser />
                </div>
                <input
                  type="text"
                  placeholder="이메일 아이디"
                  css={{
                    backgroundColor: theme === "light" ? "#f6f3f2" : "rgb(35, 47, 69)",
                    color: themeColor,
                    ":autofill": { "-webkit-text-fill-color": `${themeColor} !important`},
                  }}
                  {...register("email", {
                    required: "이메일은 필수 입력입니다.",
                    pattern: {
                      value: /\S+@\S+\.\S+/,
                      message: "이메일 형식에 맞지 않습니다.",
                    },
                  })}
                />
              </div>
              {errors.email && (
                <span className="errorTxt">{errors.email.message}</span>
              )}
            </div>
            <div>
              <div className="wIcon_area">
                <div className="left_icon">
                  <FiLock />
                </div>
                <input
                  type={passwordShow ? "text" : "password"}
                  placeholder="비밀번호"
                  css={{ backgroundColor: theme === "light" ? "#f6f3f2" : "rgb(35, 47, 69)", color: themeColor }}
                  {...register("password", {
                    required: "비밀번호는 필수 입력입니다.",
                    minLength: {
                      value: 4,
                      message: "4자리 이상 비밀번호를 입력하세요.",
                    },
                  })}
                />
                <div className="password_icon" onClick={handlePasswordShow}>
                  {passwordShow ? <BsEye /> : <BsEyeSlash />}
                </div>
              </div>
              {errors.password && (
                <span className="errorTxt">{errors.password.message}</span>
              )}
            </div>
            <div className="infoConfigArea">
              <div className="rememberArea">
                <input
                  type="checkbox"
                  id="rememberId"
                  checked={rememberCheck}
                  onChange={handleChangeRemember}
                  css={{
                    border: theme === "light" ? "1px solid #121212" : "1px solid #dddddd",
                    ":after": { border: theme === "light" ? "1px solid #121212" : "1px solid #dddddd"},
                  }}
                />
                <label htmlFor="rememberId">계정정보 저장하기</label>
              </div>
            </div>
            <p {...register("loginError")}>
              {errors.loginError && (
                <span className="errorLogin">{errors.loginError.message}</span>
              )}
            </p>
          </div>
          <button
            type="submit"
            disabled={isSubmitting}
            css={{ color: theme === "light" ? "#121212" : "#dddddd"}}
          >
            로그인
          </button>
        </form>
      </div>
    </div>
  );
}

Login.auth = false;

 

 

결과