React Native集成Supabase问题:用户返回Null且认证状态不持久
React Native 中 Supabase 认证与用户信息获取问题
我刚开始学 React Native,发现 React 里用 Supabase 和 Flutter 里的用法差很多。现在已经实现了邮箱登录/注册,也能通过监听认证状态切换导航栈,但碰到两个关联问题:
问题1:应用重启后丢失登录状态
关闭应用重新打开,还是显示登录界面,明明之前已经登录过了。我试过设置包括 localStorage 在内的选项,但没用。我的 supabaseClient.tsx 代码如下:
const options = { auth: { localStorage: AsyncStorage as any, autoRefreshToken: true, persistSession: true, detectSessionInUrl: true, }, }; const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, options); export { supabase };
问题2:HomeScreen 无法获取已登录用户的 displayName
想在 HomeScreen 显示用户设置的 displayName,但 getUser() 和 getSession() 返回的用户都是 Null,拿不到 user.id,导致 displayName 未定义,页面空白。获取 displayName 的代码如下:
export function HomeScreen() { const [displayName, setDisplayName] = useState(); useEffect(() => { (async () => { const user = (await supabase.auth.getSession()).data.session?.user; console.log("User: " + user); const { data, error } = await supabase .from("profiles") .select() .eq("uid", user?.id); if (error === null) { data!.map((data) => { const name = data.displayName; console.log(name); setDisplayName(name); }); } else { console.log(error.message); } console.log("Name: " + displayName); })(); }, [setDisplayName]); return ( <View> <Text>{displayName}</Text> </View> ); }
解决方案
针对问题1:修复会话持久化
React Native 里不能直接把 AsyncStorage 传给 localStorage 字段,Supabase 官方为 React Native 提供了专门的存储适配器,需要用 @supabase/auth-storage-react-native 包:
- 安装依赖:
npm install @supabase/auth-storage-react-native @react-native-async-storage/async-storage
- 修改
supabaseClient.tsx:
import AsyncStorage from '@react-native-async-storage/async-storage'; import { createClient } from '@supabase/supabase-js'; import { ReactNativeStorage } from '@supabase/auth-storage-react-native'; const storage = new ReactNativeStorage(AsyncStorage); const options = { auth: { storage, autoRefreshToken: true, persistSession: true, detectSessionInUrl: false, // React Native 无网页跳转场景,无需开启 }, }; const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, options); export { supabase };
另外,应用启动时不要直接跳转登录页,要先通过 supabase.auth.initializeSession() 或监听 authStateChange 确认会话状态后再做页面跳转。
针对问题2:正确获取用户会话与信息
getSession() 是异步操作,应用启动时会话可能还未加载完成,直接在 useEffect 调用会拿不到数据。应该监听认证状态变化,确保会话就绪后再获取用户信息:
import { useEffect, useState } from 'react'; import { View, Text } from 'react-native'; import { supabase } from './supabaseClient'; export function HomeScreen() { const [displayName, setDisplayName] = useState<string | null>(null); const [loading, setLoading] = useState(true); useEffect(() => { // 监听认证状态变化 const subscription = supabase.auth.onAuthStateChange(async (event, session) => { if (session?.user) { // 会话存在,获取用户信息 const { data, error } = await supabase .from("profiles") .select("displayName") .eq("uid", session.user.id) .single(); // 单个用户对应唯一profile,用single()替代map if (!error && data) { setDisplayName(data.displayName); } else { console.log(error?.message || '获取用户信息失败'); } } else { // 无会话时清空显示名 setDisplayName(null); } setLoading(false); }); // 组件卸载时取消订阅,避免内存泄漏 return () => subscription.unsubscribe(); }, []); if (loading) { return <View><Text>加载中...</Text></View>; } return ( <View> <Text>{displayName || '未设置昵称'}</Text> </View> ); }
关键改进点:
- 用
onAuthStateChange监听状态,确保会话加载完成后再获取数据 - 用
single()替代数组map,简化单条数据的处理逻辑 - 添加加载状态,避免页面空白
- 组件卸载时取消订阅,防止内存泄漏
内容的提问来源于stack exchange,提问作者Globe
相关产品推荐
相关产品推荐

