You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 包:

  1. 安装依赖:
npm install @supabase/auth-storage-react-native @react-native-async-storage/async-storage
  1. 修改 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:35:16