0. 이슈 발생 과정
1. 카카오 로그인
2. 서버 콜백 라우트에서 user테이블에 가입 시킴 ( members 테이블에 없으면 )
3. 로그인 됨
내 로그인 로직 순서는,
위와 같은 순서로 로그인이 된다.
supabase에서 `onAuthStateChange` 으로 session.user 데이터를 받아올 수 있는데
session.user에 들어가는 데이터 형식과, 내가 members테이블에 집어넣은 데이터형식이 달랐다.
(예를들면,session.user에는 user_name 이라고 나오고, members 테이블에 집어넣은 데이터는 nickname임)
어쩔수 없이 onAuthStateChange의 콜백형식으로 session.user를 불러오면 session.user.id를 토대로 다시한번 supabase 쿼리문을 작성하여 members테이블을 조회해서 저장하는식으로 구현하려고 했었다.
onAuthStateChange: Supabase의 인증 상태 변화를 감지하는 리스너다.
1. 이슈 발생
하지만 onAuthStateChange의 콜백으로 받아온 session.user.id는 console.log()에 잘찍히는 반면,
supabase.from('members')... 하는거는 동작을 하질 않았는데..
'use client'
import { useUserStore } from '@/store/userStore'
import { createClient } from '@/utils/supabase/client'
import { useEffect, useState } from 'react'
export function AuthStateManager({ children }: { children: React.ReactNode }) {
const supabase = createClient()
const setUser = useUserStore((state) => state.setUser)
useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(async (event, session) => {
if (event === 'SIGNED_OUT') {
setUser(null)
}
// 원인
if (session?.user) {
console.log(session.user.id)
const { data, error } = await supabase
.from('members')
.select('*')
.eq('id', '938c0cff-d7bd-4356-b566-fd0d698097b0')
.single()
if (error) {
setUser(null)
throw error
}
setUser(data)
}
})
return () => subscription.unsubscribe()
}, [setUser, supabase])
return children
}
export function AuthProvider({ children }: { children: React.ReactNode }) {
return <AuthStateManager>{children}</AuthStateManager>
}
2. 해결
온 곳을 뒤져봤는데 찾은 결론은 다음과 같다.
1. supabase.auth.onAuthStateChange에 콜백으로 async, await 쓰지마라.
2. supabase.auth.onAuthStateChange의 콜백으로 supabase 다른 쿼리문을 쓰면 안된다.
3. 정 필요하다면 콜백 실행이 완료된 다음 setTimeout을쓰고 그안에 supabase 쿼리문을 써라!
짧막하게 왜 쓰면안되냐면.. 데드락이 발생할 수 있어서 라고한다.
즉, 내가 이슈를 발생시킨 원인은 '데드락' 때문이였다.
이와 같은 해결법을 가지고 새롭게 코드를 짜봤다.
'use client'
import { useUserStore } from '@/store/userStore'
import { createClient } from '@/utils/supabase/client'
import { useEffect } from 'react'
export function AuthStateManager({ children }: { children: React.ReactNode }) {
const supabase = createClient()
const setUser = useUserStore((state) => state.setUser)
useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_OUT') {
setUser(null)
}
setTimeout(async () => {
// 콜백 완료 후 다음 이벤트 루프에서 쿼리 실행
if (session?.user) {
const { data } = await supabase
.from('members')
.select('*')
.eq('id', session.user.id)
.single()
setUser(data)
}
}, 0)
})
return () => subscription.unsubscribe()
}, [setUser, supabase])
return children
}
export function AuthProvider({ children }: { children: React.ReactNode }) {
return <AuthStateManager>{children}</AuthStateManager>
}
3. 참고자료
https://supabase.com/docs/reference/javascript/auth-onauthstatechange
'이슈 저장소' 카테고리의 다른 글
'apollo-upload-client' 모듈을 찾을 수 없었던 이슈.. (0) | 2024.08.23 |
---|---|
로그인된 사용자, 로그인 페이지에서 홈으로 리다이렉션 시 UI 깜빡임 문제 이슈 (0) | 2024.08.14 |