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

React Native+Firebase中用AsyncStorage更新用户头像报错

React Native Expo项目更新用户头像时出现Promise拒绝错误

在基于Expo的React Native项目中,通过AsyncStorage存储登录用户会话,App.js中用状态管理会话,但在Profile页面尝试更新用户头像时,触发错误:Possible Unhandled Promise Rejection: TypeError: undefined is not a function。

相关代码

App.js

const AuthenticatedUserProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  return (
    <AuthenticatedUserContext.Provider value={{ user, setUser }}>
      {children}
    </AuthenticatedUserContext.Provider>
  );
};

function RootNavigator() {
  const auth = getAuth();
  const { user, setUser } = useContext(AuthenticatedUserContext);
  const [sesiones, setSesiones] = useState(null);

  useEffect(() => {
    const storeData = async (user) => {
      try {
        await AsyncStorage.setItem("cookie", JSON.stringify(user));
      } catch (e) {}
    };

    const obtenerSesion = async () => {
      try {
        const session = await AsyncStorage.getItem("cookie");
        setSesiones(JSON.parse(session));
      } catch (e) {}
    };

    if (user) {
      storeData(user);
      obtenerSesion();
    }

    if (!user) {
      obtenerSesion();
    }

    const unsubscribe = onAuthStateChanged(auth, async (authenticatedUser) => {
      authenticatedUser ? setUser(authenticatedUser) : setUser(null);
    });

    return () => unsubscribe();
  }, [user]);


  return (
    <NavigationContainer>
      {user || sesiones ? <AppNavigation /> : <GuestNavigation />}
    </NavigationContainer>
  );
}

export default function App() {
  return (
    <>
      <AuthenticatedUserProvider>
        <RootNavigator />
      </AuthenticatedUserProvider>

      <Toast />
    </>
  );
}

Profile.js

const uploadImage = async (uri) => {
    setLoading(true);
    const imageBlob = [];
    const metadata = {
      contentType: "image/jpeg",
    };
    const img = await fetch(uri);
    const blob = await img.blob();
    const storage = getStorage();
    const archivoRef = ref(storage, `avatar/${id()}`);
    uploadBytes(archivoRef, blob, metadata).then((snapshot) => {
      updatePhotoAvatar(snapshot.metadata.fullPath);
    });
  };

  const updatePhotoAvatar = async (imagePath) => {
    try {
      const storage = getStorage();
      const archivoRef = ref(storage, imagePath);
      const imageUrl = await getDownloadURL(archivoRef);
      updateProfile(photoURLs, { photoURL: imageUrl });//错误触发行
      setAvatar(imageUrl);
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  };

问题原因

错误核心是调用updateProfile时传入的第一个参数不符合要求:

  • updateProfile是Firebase Auth提供的方法,要求第一个参数是Firebase Auth实例化的用户对象(即auth.currentUser)
  • 当前代码传入的photoURLs是从AsyncStorage中获取的序列化用户数据(JSON解析后的普通对象),该对象没有updateProfile所需的内部方法,因此触发undefined is not a function错误

解决方案

1. 正确传入Firebase Auth用户对象

在Profile.js中获取Auth实例,使用auth.currentUser作为updateProfile的第一个参数,同时同步更新AsyncStorage中的用户数据:

// 在Profile.js顶部获取Auth实例
const auth = getAuth();

const updatePhotoAvatar = async (imagePath) => {
  try {
    const storage = getStorage();
    const archivoRef = ref(storage, imagePath);
    const imageUrl = await getDownloadURL(archivoRef);
    
    // 修正:传入auth.currentUser而非序列化的photoURLs
    await updateProfile(auth.currentUser, { photoURL: imageUrl });
    
    setAvatar(imageUrl);
    setLoading(false);
    
    // 同步更新本地缓存的用户数据
    const updatedUser = { ...auth.currentUser, photoURL: imageUrl };
    await AsyncStorage.setItem("cookie", JSON.stringify(updatedUser));
  } catch (error) {
    console.log("更新头像失败:", error);
    setLoading(false);
  }
};

2. 统一异步逻辑风格并完善错误处理

将uploadImage中的.then()改为await,保持代码风格一致,同时覆盖所有异常场景:

const uploadImage = async (uri) => {
  setLoading(true);
  try {
    const metadata = {
      contentType: "image/jpeg",
    };
    const img = await fetch(uri);
    const blob = await img.blob();
    const storage = getStorage();
    const archivoRef = ref(storage, `avatar/${id()}`);
    const snapshot = await uploadBytes(archivoRef, blob, metadata);
    await updatePhotoAvatar(snapshot.metadata.fullPath);
  } catch (error) {
    console.log("上传图片失败:", error);
    setLoading(false);
  }
};

3. 优化App.js的会话同步逻辑

在App.js的obtenerSesion函数中处理session为null的情况,避免JSON解析报错,同时移除重复的会话获取逻辑:

const obtenerSesion = async () => {
  try {
    const session = await AsyncStorage.getItem("cookie");
    setSesiones(session ? JSON.parse(session) : null);
  } catch (e) {
    console.log("获取会话失败:", e);
    setSesiones(null);
  }
};

// useEffect内调整会话获取逻辑
useEffect(() => {
  // ... 其他函数定义
  
  if (user) {
    storeData(user);
    // 移除重复的obtenerSesion调用,直接使用user状态即可
  } else {
    obtenerSesion();
  }
  
  // ... 其他逻辑
}, [user]);

内容的提问来源于stack exchange,提问作者yuu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:01:01