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

React应用页面刷新时从Firestore拉取数据如何避免Login组件临时渲染

问题根因

  • Redux默认将数据存储在运行内存中,页面刷新后所有状态会重置为初始值,本身不具备自动持久化能力,你认为Redux刷新后会保留数据的认知有误。
  • Firebase的onAuthStateChanged监听是异步触发的,页面刷新后到回调返回用户登录状态的间隔期内,你从Redux拿到的user初始值为null,因此会先渲染Login组件,出现闪烁问题。
  • useEffect回调中捕获的user是初始渲染时的闭包值,你在dispatch login动作后调用checkDocument(user?.uid)时,user还是初始的null,会导致checkDocument参数错误。

修复方案

1. 新增认证加载状态,避免未完成认证时错误渲染Login

首先修改userSlice.js,新增加载状态标识:

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  userDetails: null,
  // 新增认证加载状态
  authLoading: true,
};

const userSlice = createSlice({
  name: "user",
  initialState,
  reducers: {
    login: (state, action) => {
      state.userDetails = action.payload;
      state.authLoading = false;
    },
    logout: (state) => {
      state.userDetails = null;
      state.authLoading = false;
    },
  },
});

export const { login, logout } = userSlice.actions;
export const selectUser = (state) => state.user.userDetails;
export const selectAuthLoading = (state) => state.user.authLoading;

export default userSlice.reducer;

2. 修改App.js逻辑,修复闭包问题和渲染逻辑

import { doc, getDoc, setDoc } from "@firebase/firestore";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Route, Switch } from "react-router";
import Login from "./components/Login";
import Mainthread from "./components/Mainthread";
import Notifications from "./screens/notifications";
import Profile from "./screens/profile";
import { auth, db } from "./services/Firebase";
import { login, logout, selectUser, selectAuthLoading } from "./services/redux/userSlice";

function App() {
  const user = useSelector(selectUser);
  const authLoading = useSelector(selectAuthLoading);
  const dispatch = useDispatch();

  async function createDocument(id, data) {
    await setDoc(doc(db, "users", id), data);
  }

  // 直接接收authUser参数,不依赖外部的user变量
  async function checkDocument(authUser) {
    const docRef = doc(db, "users", authUser.uid);
    const docSnap = await getDoc(docRef);
    if (docSnap.exists()) {
      console.log("your document exists with us...");
    } else {
      const data = { email: authUser.email };
      createDocument(authUser.uid, data);
      console.log("your document is being created...");
    }
  }

  useEffect(() => {
    // onAuthStateChanged本身返回取消监听的函数,不需要额外包一层
    const unsubscribe = auth.onAuthStateChanged(function (authUser) {
      if (authUser) {
        dispatch(
          login({
            uid: authUser.uid,
            email: authUser.email,
          })
        );
        // 直接传入回调返回的authUser
        checkDocument(authUser);
      } else {
        dispatch(logout());
        console.log("Logged Out!");
      }
    });
    // 组件卸载时取消监听,避免内存泄漏
    return unsubscribe;
  }, [dispatch]);

  // 认证未完成时渲染加载占位,避免闪烁Login
  if (authLoading) {
    return <div>加载中...</div>
  }

  return (
    <>
      <Switch>
        <Route path="/notifications">
          <Notifications />
        </Route>
        <Route path="/profile">
          <Profile />
        </Route>
        <Route path="/">{user ? <Mainthread /> : <Login />}</Route>
      </Switch>
    </>
  );
}

export default App;

可选:Redux数据持久化配置

如果需要将Redux中的用户信息持久化到本地存储,避免每次刷新都需要重新拉取额外的用户字段,可以接入redux-persist,修改store配置如下:

import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';
import storage from 'redux-persist/lib/storage';
import { persistReducer, persistStore } from 'redux-persist';
import { combineReducers } from '@reduxjs/toolkit';

const persistConfig = {
  key: 'root',
  storage,
  whitelist: ['user'] // 只持久化user模块
};

const rootReducer = combineReducers({
  user: userReducer
});

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
    }),
});

export const persistor = persistStore(store);

之后在入口文件用PersistGate包裹App组件即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 09:39:03