CHZZK-Study / Grass-Diary-Client

취지직 2팀 프로젝트 Grass Diary
1 stars 3 forks source link

:recycle: refactor: useAuth hook recoil에서 zustand로 변경 #163

Closed ccconac closed 2 months ago

ccconac commented 2 months ago

✅ 체크리스트

📝 작업 상세 내용

⚡️ authState.ts → authStore.ts

zustand는 저장소라는 작명을 보편적으로 사용하고 있어 기존 recoil 라이브러리를 사용할 때 작명인 state를 store로 변경해 주었습니다. 또한 코드가 위에서 아래로 변경되었습니다.

import { atom } from 'recoil';

const isAuthenticatedAtom = atom<boolean>({
  key: 'isAuthenticated',
  default: false,
});

const isLoadingAtom = atom<boolean>({
  key: 'isLoding',
  default: true,
});

export { isAuthenticatedAtom, isLoadingAtom };
import create from 'zustand';

// 타입
interface AuthState {
  isAuthenticated: boolean;
  isLoading: boolean;
  setIsAuthenticated: (isAuthenticated: boolean) => void;
  setIsLoading: (isLoading: boolean) => void;
}

// 상태 저장소
export const useAuthStore = create<AuthState>(set => ({
  isAuthenticated: false, // 사용자의 인증 상태 (default: false)
  isLoading: true, // 로딩 상태 (default: true → 로딩 중)
  setIsAuthenticated: isAuthenticated => set({ isAuthenticated }), // 인증 상태 업데이트 함수
  setIsLoading: isLoading => set({ isLoading }), // 로딩 상태 업데이트 함수
}));

⚡️ authSelector.ts → authUtils.ts

이름과 코드가 변경되었습니다.

import { selector } from 'recoil';
import { checkAuth } from '@utils/authUtils';
import { isAuthenticatedAtom, isLoadingAtom } from './authState';
import { CONSOLE_ERROR } from '@constants/message';

export const checkAuthSelector = selector<boolean>({
  key: 'checkAuthSelector',
  get: async ({ get }) => {
    get(isAuthenticatedAtom);

    try {
      const isLoggedIn: boolean = await checkAuth();
      return isLoggedIn;
    } catch (error) {
      console.error(CONSOLE_ERROR.LOGIN.FALSE + error);
      return false;
    }
  },

  set: ({ set }, newValue) => {
    set(isAuthenticatedAtom, newValue);
    set(isLoadingAtom, false);
  },
});

authStore를 호출하여 setIsAuthenticatedsetIsLoading 메소드를 가져와 상태를 업데이트하는 로직을 작성해 주었습니다.

  1. 인증을 확인하기 위해 checkAuth 함수를 호출하고, 그 결과를 isLoggedIn 변수에 저장합니다. 이 결과는 사용자가 로그인 상태인지 여부를 나타냅니다.
  2. setIsAuthenticated를 호출하여 인증 상태를 업데이트하고, setIsLoading(false)를 호출해 로딩 상태를 false로 설정해 주어 상태 인증 상태를 관리합니다.
  3. checkAuth 호출 중 오류가 발생하면, 콘솔에 오류 메시지를 출력하고 setIsAuthenticated(false)를 호출하여 인증 상태를 false로 설정하고, 로딩 상태 또한 false로 설정합니다.
import { useAuthStore } from './authStore';
import { checkAuth } from '@utils/authUtils';
import { CONSOLE_ERROR } from '@constants/message';

export const useCheckAuth = () => {
  const { setIsAuthenticated, setIsLoading } = useAuthStore(state => state);

  const handleCheckAuth = async () => {
    try {
      const isLoggedIn: boolean = await checkAuth();
      setIsAuthenticated(isLoggedIn);
      setIsLoading(false);
    } catch (error) {
      console.error(CONSOLE_ERROR.LOGIN.FALSE + error);
      setIsAuthenticated(false);
      setIsLoading(false);
    }
  };

  return handleCheckAuth;
};

⚡️ useAuth.ts

useAuth는 네이밍 변경 없이 hook 내의 로직만 변경되었습니다.

import { useRecoilState, useRecoilValueLoadable } from 'recoil';
import { isAuthenticatedAtom, isLoadingAtom } from './authState';
import { checkAuthSelector } from './authSelector';
import { useEffect } from 'react';
import { CONSOLE_ERROR } from '@constants/message';

interface IUseAuthReturn {
  isAuthenticated: boolean;
  isLoading: boolean;
}

export const useAuth = (): IUseAuthReturn => {
  const [isAuthenticated, setIsAuthenticated] =
    useRecoilState<boolean>(isAuthenticatedAtom);
  const [isLoading, setIsLoading] = useRecoilState<boolean>(isLoadingAtom);

  const checkAuthLoadable = useRecoilValueLoadable<boolean>(checkAuthSelector);

  useEffect(() => {
    switch (checkAuthLoadable.state) {
      case 'hasValue':
        setIsAuthenticated(checkAuthLoadable.contents);
        setIsLoading(false);
        break;
      case 'loading':
        setIsLoading(true);
        break;
      case 'hasError':
        setIsLoading(false);
        console.error(CONSOLE_ERROR.LOGIN.FAIL);
        break;
    }
  }, [checkAuthLoadable.state]);

  return { isAuthenticated, isLoading };
};
import { useEffect } from 'react';
import { useAuthStore } from './authStore';
import { useCheckAuth } from './authUtils';

interface IUseAuthReturn {
  isAuthenticated: boolean;
  isLoading: boolean;
}

export const useAuth = (): IUseAuthReturn => {
  const { isAuthenticated, isLoading } = useAuthStore(state => state);
  const handleCheckAuth = useCheckAuth();

  // 컴포넌트가 마운트될 때 handleCheckAuth 함수를 호출 (인증 상태 확인을 위함)
  useEffect(() => {
    handleCheckAuth();
  }, [handleCheckAuth]);

  return { isAuthenticated, isLoading };
};

🚨 버그 발생 이유 (선택 사항)

🔎 후속 작업 (선택 사항)

현재 헤더의 사용자 프로필을 눌렀을 시 무한 로딩으로 인한 웹 사이트 강제 종료 이슈가 발생하고 있습니다. 모든 hook을 zustand로 교체하지 않아 생기는 문제라고 우선 추정 중이기 때문에, 만일 zustand 적용 후에도 이슈가 여전히 발생한다면 추후 작업이 필요합니다.

🤔 질문 사항 (선택 사항)

📚 참고 자료 (선택 사항)

📸 스크린샷 (선택 사항)

✅ 셀프 체크리스트

이슈 번호: #98