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

React应用绑定onChange状态时输入框卡顿无响应求助

输入框卡顿无法输入问题修复

问题描述

在输入框输入内容时页面卡顿且无法输入,该功能此前正常运行,问题突然出现。尝试添加onBlur事件、为输入框绑定value={registerEmail}后仍未解决。

原代码

import React, {useState} from 'react'
import {
    createUserWithEmailAndPassword,
    onAuthStateChanged,
    signInWithEmailAndPassword,
    signOut
} from 'firebase/auth'
import { Form, Button, Card, Container } from 'react-bootstrap'
import {auth} from '../../services/firebase-config'

export default function SignUp() {

    const [registerEmail, setRegisterEmail] = useState("")
    const [registerPassword, setRegisterPassword] = useState("")
    const [registerConfirmedPassword, setRegisterConfirmedPassword] = useState("")
    
    const [user, setUser] = useState({})

    onAuthStateChanged(auth, (currentUser) => {
        setUser(currentUser)
    })

    const register = async (event) => {
        event.preventDefault();
        try {
            const user =  await createUserWithEmailAndPassword(auth, registerEmail, registerPassword)
            console.log(user)
        }
        catch(error) {
            console.log(error.message)
        }
    }

    const login = async(event) => {
        event.preventDefault();
        try {
            const user =  await signInWithEmailAndPassword(auth, registerEmail, registerPassword)
            console.log(user)
        }
        catch(error) {
            console.log(error.message)
        }
    }

    const logout = async(event) => {
        try {
            await signOut(auth)
        }
        catch(error) {
            console.log(error.message)
        }
    }

    return (
        <Container className="d-flex align-items-center justify-content-center w-100">
            <Card className='p-3' style={{maxWidth:"400px"}}>
                <Card.Body>
                    <h2 className='text-center mb-4'>Sign Up</h2>
                    <Form>
                        <Form.Group id="email">
                            <Form.Label>Email</Form.Label>
                            <Form.Control type="email" onChange={e => setRegisterEmail(e.target.value)} required />
                        </Form.Group>
                        <Form.Group id="password">
                            <Form.Label>Password</Form.Label>
                            <Form.Control type="password" onChange={e => setRegisterPassword(e.target.value)}  required />
                        </Form.Group>
                        <Form.Group id="password-confirm">
                            <Form.Label>Password Confirmation</Form.Label>
                            <Form.Control type="password" onChange={e => setRegisterConfirmedPassword(e.target.value)} required />
                        </Form.Group>
                        { <Button className='w-100' onClick={(e) => register(e)}>Sign Up</Button>}
                    </Form>
                </Card.Body>
                <div className='w-100 text-center mt-2'>
                    Already have an account? <Button className='w-100' onClick={(e) => login(e)}>Login</Button>
                </div>
                <Button onClick={(e) => logout(e)}>Logout</Button>
            </Card>
        </Container>
    )
}

问题根源

onAuthStateChanged直接写在组件函数内部,会在每次组件渲染时重新创建监听器。监听器触发时调用setUser更新状态,这又会触发组件重新渲染,形成无限循环,导致页面资源被持续占用,出现输入卡顿甚至无法输入的情况。

修复方案

使用React.useEffect包裹onAuthStateChanged的订阅逻辑,确保只在组件挂载时订阅一次,同时在组件卸载时取消订阅,避免内存泄漏:

import React, {useState, useEffect} from 'react'
import {
    createUserWithEmailAndPassword,
    onAuthStateChanged,
    signInWithEmailAndPassword,
    signOut
} from 'firebase/auth'
import { Form, Button, Card, Container } from 'react-bootstrap'
import {auth} from '../../services/firebase-config'

export default function SignUp() {

    const [registerEmail, setRegisterEmail] = useState("")
    const [registerPassword, setRegisterPassword] = useState("")
    const [registerConfirmedPassword, setRegisterConfirmedPassword] = useState("")
    
    const [user, setUser] = useState({})

    useEffect(() => {
        // 创建监听器并保存返回的取消订阅函数
        const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
            setUser(currentUser)
        })

        // 组件卸载时取消订阅
        return unsubscribe
    }, [auth])

    const register = async (event) => {
        event.preventDefault();
        try {
            const user =  await createUserWithEmailAndPassword(auth, registerEmail, registerPassword)
            console.log(user)
        }
        catch(error) {
            console.log(error.message)
        }
    }

    const login = async(event) => {
        event.preventDefault();
        try {
            const user =  await signInWithEmailAndPassword(auth, registerEmail, registerPassword)
            console.log(user)
        }
        catch(error) {
            console.log(error.message)
        }
    }

    const logout = async(event) => {
        try {
            await signOut(auth)
        }
        catch(error) {
            console.log(error.message)
        }
    }

    return (
        <Container className="d-flex align-items-center justify-content-center w-100">
            <Card className='p-3' style={{maxWidth:"400px"}}>
                <Card.Body>
                    <h2 className='text-center mb-4'>Sign Up</h2>
                    <Form>
                        <Form.Group id="email">
                            <Form.Label>Email</Form.Label>
                            <Form.Control type="email" value={registerEmail} onChange={e => setRegisterEmail(e.target.value)} required />
                        </Form.Group>
                        <Form.Group id="password">
                            <Form.Label>Password</Form.Label>
                            <Form.Control type="password" value={registerPassword} onChange={e => setRegisterPassword(e.target.value)}  required />
                        </Form.Group>
                        <Form.Group id="password-confirm">
                            <Form.Label>Password Confirmation</Form.Label>
                            <Form.Control type="password" value={registerConfirmedPassword} onChange={e => setRegisterConfirmedPassword(e.target.value)} required />
                        </Form.Group>
                        <Button className='w-100' onClick={register}>Sign Up</Button>
                    </Form>
                </Card.Body>
                <div className='w-100 text-center mt-2'>
                    Already have an account? <Button className='w-100' onClick={login}>Login</Button>
                </div>
                <Button onClick={logout}>Logout</Button>
            </Card>
        </Container>
    )
}

额外优化点

  • 为输入框添加value属性,将其转为受控组件,确保输入框值与状态完全同步,避免潜在的状态不一致问题。
  • 简化按钮的onClick回调,直接传递函数(如onClick={register}),无需额外包裹箭头函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 14:15:41