onAuthStateChange
메소드를 초기 렌더링 시에 한 번만 실행시키면서, userInfo
state를 업데이트 하는 로직을 구성.import { useEffect } from 'react';
import { supabase } from '../api/supabaseClient';
import useAuthStore from '../../stores/useAuthstore';
import useGetUserInfo from './useGetUserInfo';
const useAuthListener = () => {
const setUserInfo = useAuthStore().setUserInfo;
const { data: userData } = useGetUserInfo();
useEffect(() => {
// 인증 상태 변경 감지 및 자동 업데이트
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(async (_, session) => {
const userInfo = {
id: session?.user.id,
email: session?.user.email,
nickname: userData?.nickname || '',
profile_img_url: userData?.profile_img_url || '',
};
setUserInfo(userInfo);
});
return () => {
subscription.unsubscribe(); // Cleanup when unmounting
};
}, []);
};
export default useAuthListener;
import { useQuery } from '@tanstack/react-query';
import getUserInfo from '../api/getUserInfo';
import useAuthStore from '../../stores/useAuthstore';
const useGetUserInfo = () => {
const userId = useAuthStore((state) => state.userInfo.id);
return useQuery({
queryKey: ['userInfo', userId],
queryFn: () => getUserInfo(userId),
enabled: !!userId,
});
};
export default useGetUserInfo;
import { supabase } from './supabaseClient';
const getUserInfo = async (authId) => {
let { data, error } = await supabase
.from('users')
.select('nickname, profile_img_url')
.eq('id', authId);
if (error) {
throw new Error(error);
}
return data;
};
export default getUserInfo;
@tanstack_react-query.js?v=6ec93a7b:2839
Uncaught Error: No QueryClient set, use QueryClientProvider to set one
at useQueryClient (@tanstack_react-query.js?v=6ec93a7b:2839:11)
at useBaseQuery (@tanstack_react-query.js?v=6ec93a7b:3040:18)
at useQuery (@tanstack_react-query.js?v=6ec93a7b:3111:10)
at useGetUserInfo (useGetUserInfo.js:21:10)
at useAuthListener (useAuthListener.js:8:30)
at App (App.jsx:9:3)
QueryClient가 세팅되어 있지 않으니,
QueryClientProvider를 사용하라는 에러가 발생했다.
App.jsx 내에서 useAuthListener
를 실행하는 위치가 잘못되었다.
queryClientProvider가 감싸고 있는 영역 안으로 넣어주어야 한다.
그래서 기존의 useEffect 코드를 컴포넌트화하여 queryClientProvider 내부에 위치시키는 것으로 파훼!
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import Router from './routes/Router';
import AuthListener from './components/auth/AuthListener';
const App = () => {
const queryClient = new QueryClient();
return (
<>
<QueryClientProvider client={queryClient}>
<AuthListener />;
<Router />
</QueryClientProvider>
</>
);
};
export default App;
import React, { useEffect } from 'react';
import { supabase } from '../../libs/api/supabaseClient';
import useAuthStore from '../../stores/useAuthstore';
import useGetUserInfo from '../../libs/hooks/useGetUserInfo';
const AuthListener = () => {
const setUserInfo = useAuthStore((state) => state.setUserInfo);
const { data: userData, isPending } = useGetUserInfo();
useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(async (_, session) => {
const userInfo = {
id: session?.user.id,
email: session?.user.email,
nickname: userData?.nickname || '',
profile_img_url: userData?.profile_img_url || '',
};
setUserInfo(userInfo);
});
// cleanUp
return () => {
subscription.unsubscribe();
};
}, [userData]); // userData 변경 시 리렌더링
if (isPending) return <>기다려.</>;
return <></>;
};
export default AuthListener;
onAuthStateChange
로 불러오는 로직은 그냥 수행되도록 두고, userData
변동 시 setUserInfo
로 유저 정보를 업데이트 하는 로직을 시도해 보았다. useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(async (_, session) => {
const userInfo = {
id: session?.user.id,
email: session?.user.email,
nickname: userData?.nickname || '',
profile_img_url: userData?.profile_img_url || '',
};
setUserInfo(userInfo);
});
return () => {
subscription.unsubscribe();
};
}, []); // userData 의존성 배열 삭제
useEffect(() => {
if (!userData) {
return;
}
setUserInfo((prev) => ({
...prev,
nickname: userData.nickname,
profile_img_url: userData.profile_img_url,
}));
console.log('final ===>');
}, [userData]);
파일 내에서 저장을 한 번 누르면 닉네임 값이 들어가는 걸 볼 수 있다.
다만 브라우저에서 새로고침을 하면 다시 원점 복귀.
일단 첫번째 방향으로 진행하면서 추후 개선해보는 방식으로 종결.
여전히 초기 렌더링 시에 여러번 리렌더링이 발생하는 성능 상의 결점이 있다.
일단 결과값은 잘 불러와지니까 리드타임 내 프로젝트 완수를 위해서 잠시 미뤄두기로 ...