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
相关产品推荐
相关产品推荐

