개발자 박가나
내일배움캠프 80일차 ('한잔해' 트러블슈팅) 본문
'한잔해' 프로젝트에서 겪은 트러블슈팅을 기록하고자 한다.
문제 파악
로그인 성공 시 유저 정보를 zustand에 저장하고 이후 유저 정보가 필요할 때마다 매번 API를 호출하는 것이 아니라 zustand에 저장된 유저 정보를 가져와서 사용하도록 구현하였는데, 로그인을 성공했음에도 불구하고 유저 정보를 제대로 받아오지 못하고 새로고침을 해야 비로소 유저 정보를 받아오는 문제가 발생하였다.
시행착오
'use client';
import { createContext, useContext, useEffect, useState } from 'react';
import { useAuthStore } from '@/store/authStore';
import { SignInDataType } from '@/types/Auth';
import { fetchUser, signout } from '../actions/auth';
const AuthContext = createContext(null);
export const AuthProvider = ({ children }) => {
const { user, setUser, removeUser } = useAuthStore();
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
const fetchSignedUser = async () => {
try {
setUser(await fetchUser());
setIsAuthenticated(true);
} catch (error) {
setUser(null);
setIsAuthenticated(false);
}
};
fetchSignedUser();
}, [isAuthenticated]);
/* 로그인 */
const login = async (values: SignInDataType) => {
try {
await signin();
setIsAuthenticated(true);
} catch (error) {
throw error;
}
};
/* 로그아웃 */
const logout = async () => {
try {
await signout();
removeUser();
setIsAuthenticated(false);
} catch (error) {
throw error;
}
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
export const fetchUser = async (): Promise<UserType | null> => {
const supabase = createClient();
const {
data: { user },
error: authError,
} = await supabase.auth.getUser();
if (authError || !user) {
return null;
}
const { data: userData, error: userError } = await supabase
.from('users')
.select('*')
.eq('id', user.id)
.single();
if (userError || !userData) {
throw new Error(userError.message || '유저 정보를 가져올 수 없습니다.');
}
return {
id: userData.id,
nickname: userData.nickname,
profile_image: userData.profile_image || null,
agree_terms: userData.agree_terms,
};
};
기존 코드를 살펴보면 다음 3가지 동작이 발생할 때마다 fetchUser()의 결과값을 zustand의 user에 반영해주고 있다.
- 서비스에 처음 접속했을 때
- 화면이 새로고침 됐을 때
- isAuthenticated 값이 변경될 때
코드에는 문제가 없는 것 같은데 왜 원하는대로 동작을 안하지? 라는 생각을 하면서 fetchUser() 코드를 살펴보는 순간 원인을 알게 되었다. fetchUser() 코드를 살펴보면 getUser()에서 오류가 발생하거나 user 데이터를 반환해주지 않는 경우 에러가 아닌 null 값을 반환하고 있다.
즉, fetchUser()가 null을 반환하게 되면 에러가 나는 상황이 아니기 때문에 isAuthenticated에 true를 적용해주게 되고, 그렇게 되면 로그인을 성공해도 isAuthenticated가 이미 true이기 때문에 useEffect가 실행되지 않아서 setUser()가 실행되지 않게 되는 것이다.
useEffect(() => {
const fetchSignedUser = async () => {
try {
const currentUser = await fetchUser();
setUser(currentUser);
setIsAuthenticated(!!currentUser);
} catch (error) {
setUser(null);
setIsAuthenticated(false);
}
};
fetchSignedUser();
}, [isAuthenticated]);
최종적으로, 단순히 fetchUser()에서 에러가 발생하지 않는다고 무조건 isAuthenticated를 true로 적용하는 것이 아니라 반환값에 따라 적용해줌으로써 문제를 해결할 수 있었다.
'트러블슈팅' 카테고리의 다른 글
내일배움캠프 77일차 ('한잔해' 트러블슈팅) (0) | 2025.01.20 |
---|---|
내일배움캠프 60일차 ('냠냠로그' 트러블슈팅) (0) | 2024.12.24 |
내일배움캠프 55일차 ('League of Legends' 트러블슈팅) (1) | 2024.12.17 |
내일배움캠프 54일차 ('League of Legends' 트러블슈팅) (0) | 2024.12.16 |
내일배움캠프 52일차 ('League of Legends' 트러블슈팅) (1) | 2024.12.12 |