쿠키에 토큰(jwt)을 저장하거나 로그인 페이지 구성 시 id같은 사용자 정보를 저장하는 등 react-cookie 라이브러리를 활용하는 경우가 많 react-cookie에 대해 정리해보았다.
cookie?
쿠키는 사용자 웹 사이트 방문 시 생기는 4KB 이하의 작은 파일로 키와 값이 들어있는 데이터 파일 이다. 쿠키는 사용자가 페이지를 얼마나 자주 방문하는지 알려줌으로써, 사용자가 관심을 갖는 정보를 파악할 수 있도록 해주는 역할을 한다. 예를 들어 쇼핑몰 사이트의 장바구니를 상품을 넣고 며칠 후에 방문했을 때, 상품이 그래도 유지되어있는 이유는 쿠키를 활용하기 때문이다.
react-cookie
react-cookie npm
https://www.npmjs.com/package/react-cookie
설치
npm install react-cookie // or yarn add react-cookie
기본 사용법
const [cookies, setCookie, removeCookie] = useCookies(['cookie-name']);
⭐옵션 중 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;
결과