티스토리 뷰

문제 상황

회원 가입 폼을 만들던 중 발생한 문제이다. 로컬 스토리지에 값이 저장 되지 않는다

SSO 로그인을 해서 구글에서 유저 정보를 가져오면, 로컬 스토리지에 저장한다
그 후, 회원 정보를 등록 할 때, 저장된 정보를 가져오는 단순한 로직이다

  • 로그인 페이지
setStorage("#user", JSON.stringify(data));
  • getStorage/setStorage
// Function to store a string value in local storage using AES encryption
export function setStorage(key: string, value: string) {
  const storage = new LocalStorage(); // Create a new instance of the typescript-web-storage library
  const data = CryptoJS.AES.encrypt(value, SECRET_KEY); // Use the CryptoJS AES function to encrypt the input value
  storage.setItem<string>(key, data.toString()); // Store the encrypted value in local storage
}

// Function to retrieve a previously stored string value from local storage
export function getStorage(key: string) {
  const storage = new LocalStorage(); // Create a new instance of the typescript-web-storage library
  const data = CryptoJS.AES.decrypt(
    storage.getItem<string>(key) ?? "", // Retrieve the stored value, if it exists
    SECRET_KEY
  ).toString(CryptoJS.enc.Utf8); // Use the CryptoJS AES function to decrypt the stored value
  return data; // Return the decrypted value
}

해결 : 상태 관리

import { atom, AtomEffect } from "recoil";
import { getStorage, setStorage } from "utils/SecureStorage";

const localStorageEffect =
  (key: string) =>
  ({ setSelf, onSet }: any) => {
    const savedValue = getStorage(key);
    if (savedValue !== null) {
      setSelf(savedValue);
    }
    onSet((newValue: any, _: any, isReset: boolean) => {
      console.log("new Value : ", newValue);
      setStorage(key, JSON.stringify(newValue));
      console.log("newvalue, isReset : ", newValue, isReset);
    });
  };
export const userState = atom({
  key: "userState",
  default: getStorage("#user") || null,
  effects: [localStorageEffect("#user")],
});

먼저 userState를 선언한다. 이제 유저 데이터를 가져올 때 기본 값으로, storage 값을 가져온다.
recoil의 atom는 리액트의 state 처럼 사용 가능하다.

userState의 effects 부분이 핵심으로 useEffect와 비슷한 기능을 한다.
localStorageEffect는 state 값의 변화가 생길 경우, 작동한다

#user 값이 변경 될 경우, 앞서 만들어뒀던 setStorage에 string 형식으로 데이터를 입력하고, 로컬 스트리지에 저장한다

마치며

recoil을 사용하면 가볍게 상태 관리를 할 수 있다.
useEffect 로그를 찍어보면, 생각보다 자주 실행 되는 것을 보는데, useEffect 없이 recoil을 사용하는 것도 괜찮을 듯하다

const Login = () => {
  const [storedUser, setStoredUser] = useRecoilState(userState);
  const navigate = useNavigate();
  const handleLoginSuccess = async (code: string) => {
    const { data } = await axios.post(
      "http://localhost:4000/auth/google/callback",
      { code }
    );
    setStoredUser(data);
    const { status } = data;
    const { ssoid, userid } = data;
    if (status == "REGISTER") {
      //TODO: 회원 가입 폼 이동
      console.log("회원 가입하시죠");
      navigate("/register");
    } else {
      //TODO: 바로 로그인
      console.log("로그인 process 진행하시죠");
      const result = await axios.post(
        "http://localhost:4000/auth/token",
        {
          userid: userid,
          ssoid: ssoid,
        },
        { withCredentials: true }
      );
      console.log("result : ", result);
      // navigate("/");
    }
  };
};
728x90