스터디/사이드 프로젝트

01. Zustand로 상태관리 하기

개발자 화진 2024. 10. 6. 19:35

지금까지 리액트 프로젝트는 2번 정도 진행 했었는데 상태 관리 라이브러리를 적용해 본 경험이 없어서

이번 프로젝트에서는 zustand를 활용하여 상태관리를 해보고자 한다.

 


https://zustand.docs.pmnd.rs/getting-started/introduction

Zustand란?

  • React 상태 관리 라이브러리
  • hook를 기반으로 한 간결하고 직관적인 API를 제공하며, 전역 상태 관리를 간단하게 구현할 수 있게 해준다.

Persist와 같이 사용하기

Zustand의 미들웨어 중 하나로, 상태를 브라우저의 저장소에 저장할 수 있게 해준다. 이를 통해 페이지를 새로고침하거나 브라우저를 닫고 다시 열어도 상태가 유지되도록 할 수 있다.

 

Zustand 설치

npm install zustand

 

src/store/authStore.ts 파일 생성

  • zustand import
  • 인터페이스 정의 : 스토어의 상태와 액션 타입을 명시
interface UserInfo {
    email: string;
    nickname: string;
}

interface AuthState {
    isLoggedIn: boolean;
    userInfo: UserInfo | null;
    errorMessage: string;
    login: (email: string, password: string) => Promise<void>;
    logout: () => void;
}
  • 스토어 생성
    • create : 스토어 생성
    • persist : 상태를 localStorage에 저장할 수 있게 설정
    • 상태 초기값 설정
    • 함수 설정
    • name : 상태 저장할 키 값
    • storage : localStorage 사용하도록 설정
const useAuthStore = create<AuthState>()(
    persist(
        (set) => ({
            isLoggedIn: false,
            userInfo: null,
            errorMessage: '',
            login: async (email, password) => {
                const user = await gf_login(email, password);
                if (user) {
                    set({ isLoggedIn: true, userInfo: user, errorMessage: '' });
                } else {
                    set({ isLoggedIn: false, userInfo: null, errorMessage: '로그인 정보가 올바르지 않습니다.' });
                }
            },
            logout: () => set({ isLoggedIn: false, userInfo: null, errorMessage: '' }),
        }),
        {
            name: 'loginUserInfo', // 저장할 키
            storage: createJSONStorage(() => localStorage),
        }
    )
);

무한 루프 오류 발생

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

 

zustand로 로그인 기능 연결 후 메인으로 넘어오니 무한 루프 오류가 발생했다.

원인

 const { userInfo, isLoggedIn } = useAuthStore(state => ({
     userInfo: state.userInfo,
     isLoggedIn: state.isLoggedIn,
}));

useAuthStore를 호출할 때, 상태의 일부가 변경되면 해당 컴포넌트는 리렌더링되는데, 두 상태를 함께 destructuring 하면서 이 상태들이 각각 업데이트될 때마다 리렌더링이 발생하면서 무한 루프가 발생한 것 같다.

해결

const userInfo = useAuthStore(state => state.userInfo);
const isLoggedIn = useAuthStore(state => state.isLoggedIn);

각 상태를 별도의 useAuthStore 호출로 구독하도록 코드를 수정했다.