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

Firestore每次重载应用创建新用户致历史数据丢失问题排查

应用重启后丢失Firebase匿名凭证、生成新用户问题修复

核心问题原因

你的代码存在3处直接导致认证状态丢失的错误:

  • 未导入Firebase核心库,仅导入了auth、firestore的兼容插件,运行时全局firebase对象缺失,认证持久化逻辑完全失效
  • 认证状态监听逻辑时序错误:onAuthStateChanged在SDK初始化阶段首次触发时必然返回null(此时SDK还未完成本地缓存凭证的读取),你的逻辑检测到null就立刻调用匿名登录,直接覆盖了本地可能存在的旧用户凭证,强制生成新用户
  • 未显式配置React Native环境下的Firebase Auth持久化策略,默认配置不会将匿名用户凭证写入本地存储,应用关闭后凭证直接被清除
    另外App.js中存在冗余代码:重复定义了两次renderList方法,且将Fire实例赋值给全局变量存在引用丢失风险。

修复步骤

1. 修正Fire.js代码

首先补全Firebase核心导入,添加持久化配置,调整认证监听逻辑:

// 补全核心库导入
import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import 'firebase/compat/auth';

const firebaseConfig = {
    // 填入你自己的Firebase配置项
};

class Fire {
    constructor(callback) {
        this.init(callback);
    }
    init(callback) {
        if (!firebase.apps.length) {
            firebase.initializeApp(firebaseConfig);
        }

        // 显式设置本地持久化,凭证将存储在设备本地,重启应用不丢失
        firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
            .then(() => {
                firebase.auth().onAuthStateChanged(user => {
                    if (user) {
                        // 已存在登录用户(包括本地缓存的匿名用户),直接返回
                        callback(null, user);
                    } else {
                        // 无有效用户时才发起新的匿名登录
                        firebase
                            .auth()
                            .signInAnonymously()
                            .catch(error => {
                                callback(error);
                            });
                    }
                });
            })
            .catch(err => callback(err));
    }
    getLists(callback) {
        let ref = this.ref.orderBy('name');

        this.unsubscribe = ref.onSnapshot(snapshot => {
            const lists = []; // 补全变量声明,避免隐式全局变量污染

            snapshot.forEach(doc => {
                lists.push({ id: doc.id, ...doc.data() });
            });

            callback(lists);
        });
    }

    addList(list) {
        let ref = this.ref;
        ref.add(list);
    }

    updateList(list) {
        let ref = this.ref;
        ref.doc(list.id).update(list);
    }

    deleteList(list) {
        let ref = this.ref;
        ref.doc(list.id).delete();
    }

    get userId() {
        return firebase.auth().currentUser.uid;
    }

    get ref() {
        return firebase
            .firestore()
            .collection('users')
            .doc(this.userId)
            .collection('lists');
    }

    detach() {
        // 增加空判断,避免未初始化时调用报错
        if (this.unsubscribe) {
            this.unsubscribe();
        }
    }
}

export default Fire;

2. 修正App.js代码

将Fire实例挂载到组件实例上避免全局污染,删除冗余的重复方法定义:

// 其余导入保持不变
export default class App extends React.Component {
    state = {
        addTodoVisibile: false,
        lists: [],
        user: {},
        loading: true,
    };

    componentDidMount() {
        // 将firebase实例挂载到组件this上,不要用全局变量
        this.firebase = new Fire((error, user) => {
            if (error) {
                return alert('Something went wrong');
            }

            this.firebase.getLists(lists => {
                this.setState({ lists, user, loading: false });
            });

            this.setState({ user });
        });
    }

    componentWillUnmount() {
        this.firebase.detach();
    }

    toggleAddTodoModal() {
        this.setState({ addTodoVisibile: !this.state.addTodoVisibile });
    }

    addList = list => {
        this.firebase.addList({
            name: list.name,
            color: list.color,
            todos: [],
        });
    };

    updateList = list => {
        this.firebase.updateList(list);
    };

    deleteList = list => {
        this.firebase.deleteList(list);
    };

    // 删除之前重复定义的第一个renderList,只保留带deleteList参数的版本
    renderList = list => {
        return (
            <TodoList
                list={list}
                updateList={this.updateList}
                deleteList={this.deleteList}
            />
        );
    };

    // render方法和样式部分保持原有代码不变即可
}

验证说明

修复后首次启动应用会生成一个匿名用户,该用户的凭证会被持久化存储在设备本地。后续关闭重开应用时,SDK会自动读取本地凭证恢复登录状态,直接拉取对应用户下存储的笔记列表,不会再生成新用户。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:18:18