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

React useEffect问题:自动登录失效、userToken渲染报错

React+Firebase useEffect自动登录问题修复

问题原因

问题1:点击提交不触发登录、手动调用方法崩溃

  • Firebase初始化、数据库实例创建逻辑写在组件函数体内,组件每次重渲染都会重复执行initializeApp,Firebase不允许重复初始化同配置应用,直接抛错崩溃。
  • useEffect未传依赖数组,每次渲染都会重复执行,产生大量无效数据库请求,和重复初始化逻辑叠加进一步触发报错。
  • Firebase数据库set写入是异步操作,点击按钮触发写入后没有等待写入完成就结束流程,此时数据库中还未存入对应用户数据,读取逻辑自然拿不到值。后续输入字符触发组件重渲染、useEffect重新执行读取时,数据已经写入完成,才会出现“输一个字符才完成登录”的现象。
  • 错误使用while循环做条件渲染,React渲染流程中用同步while+return的写法存在死循环风险,属于不规范用法。

问题2:渲染{userToken}抛对象不合法错误

setuserToken存入的是snapshot.val()返回的对象,结构为{username: 输入的用户名},React不支持直接将普通JS对象作为子节点渲染,直接写{userToken}必然触发报错。

修复方案

  1. 将Firebase初始化逻辑移到组件外部,保证整个应用生命周期只初始化一次,从根源解决重复初始化崩溃问题。
  2. 给useEffect传入正确依赖数组,仅在组件首次挂载、钱包地址address变化时执行用户数据读取,避免无效请求。
  3. 将数据库写入、读取方法改为异步函数,点击提交时等待写入完成后再触发数据拉取,保证能读到最新写入的用户数据,不需要额外输入字符触发更新。
  4. 替换while条件渲染为标准的if/else条件返回,符合React渲染规范。
  5. 渲染用户信息时取对象内的具体属性(如userToken.username),不要直接渲染整个用户对象。

修复后完整代码

import React, { useState, useEffect } from "react";
import {initializeApp} from 'firebase/app';
import { getDatabase, ref, set, child, get} from 'firebase/database';

// Firebase全局初始化,仅执行一次
const clientCredentials = {
    apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
    authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
    databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
    projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
    storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
    appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
}
const app = initializeApp(clientCredentials);
const db = getDatabase();  

export default function Username(props) {
    const [userName, setUsername] = useState('');
    // 初始值设为null,区分未加载/未登录状态
    const [userToken, setuserToken] = useState(null)
    const address = props.address;
    const dbRef = ref(db);

    async function writeUserData(userId, userN) {
        const reference = ref(db, 'users/' + userId);
        await set(reference, {
            username: userN,
        });
    }

    async function connectUser() {
        try {
            const snapshot = await get(child(dbRef, `users/${address}`))
            if (snapshot.exists()) {
                setuserToken(snapshot.val());
            } else {
                console.log("No data available");
                setuserToken(null)
            }
        } catch (error) {
            console.error(error);
        }
    }

    const handleChange = (event) => setUsername(event.target.value);

    async function handleClick(e) {
        // 等待写入完成再拉取最新用户数据
        await writeUserData(address, userName);
        connectUser();
    }

    // 仅在组件挂载、address变化时执行用户校验
    useEffect(() => {
        connectUser()
    }, [address]);

    // 未登录/未加载到用户数据时返回表单
    if (!userToken) {
        return (
            <>
                <div>
                    <p className = "account-Info" >address: {address}</p>
                </div>
                <div id="form">
                    <h2 className='user-Create' > Username </h2>
                    <form id='set-User'>
                        <input id='username' className="user-Create" type='text' value={userName} onChange={handleChange} 
                        required minLength='3' maxLength='30' pattern="[a-zA-Z0-9_]+" title='only letters, numbers, and underscores.'/>
                        <button className='user-Create' type="button" onClick={handleClick}>Link Name</button>
                    </form>
                </div>
            </>
        );
    }

    // 已登录状态,取对象具体字段渲染
    return (
        <p className = "account-Info" >hi {userToken.username}</p>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:36:13