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

React页面因事件监听代码空白渲染问题求助

修复React登录/注册切换页面空白渲染问题

问题根源

你直接在组件函数顶层调用document.getElementById获取DOM元素,此时组件还未完成渲染,目标元素不存在,导致signUpButton、signInButton等变量为null,调用addEventListener时会抛出错误,最终页面无法正常渲染。同时这种直接操作DOM的方式不符合React的声明式编程模式。

解决方案

推荐两种修复方式,优先选择第二种更符合React风格的写法:

方式一:使用useRef + useEffect操作DOM

通过useRef获取DOM引用,在useEffect中(组件挂载后)添加事件监听,并在组件卸载时清理监听:

import React, { useContext, useRef, useEffect } from 'react';
import { AlertBoxContext } from '../contexts/alertbox-context';
import { AuthContext } from '../contexts/auth-context';

import '../scss/pages/NewSignup.scss'


function SignInPage() {
    const { SignUp } = useContext(AuthContext);
    const { showAlertBox } = useContext(AlertBoxContext);

    // 创建Ref引用DOM元素
    const signUpButtonRef = useRef(null);
    const signInButtonRef = useRef(null);
    const loginContainerRef = useRef(null);

    useEffect(() => {
        // 定义点击事件处理函数
        const handleSignUp = () => {
            loginContainerRef.current?.classList.add("right-panel-active");
        };

        const handleSignIn = () => {
            loginContainerRef.current?.classList.remove("right-panel-active");
        };

        // 添加事件监听
        signUpButtonRef.current?.addEventListener('click', handleSignUp);
        signInButtonRef.current?.addEventListener('click', handleSignIn);

        // 组件卸载时移除监听,防止内存泄漏
        return () => {
            signUpButtonRef.current?.removeEventListener('click', handleSignUp);
            signInButtonRef.current?.removeEventListener('click', handleSignIn);
        };
    }, []); // 空依赖数组确保仅执行一次

    return (
        <div className='pageBackground'>
            <div className="loginContainer" ref={loginContainerRef}>
                <div className="regForm-container sign-up-container">
                    <form className='regForm' action="/">
                        <h1 className='formHeader'>Create Account</h1>
                        <input type="text" placeholder="Name" />
                        <input type="email" placeholder="Email" />
                        <input type="password" placeholder="Password" />
                        <button className='formBtn'>Sign Up</button>
                    </form>
                </div>
                <div className="regForm-container sign-in-container">
                    <form className='regForm' action="/">
                        <h1 className='formHeader'>Log in</h1>
                        <input type="email" placeholder="Email" />
                        <input type="password" placeholder="Password" />
                        <h5 className='forgotPass' href="/">Forgot your password?</h5>
                        <button className='formBtn'>Log In</button>
                    </form>
                </div>
                <div className="overlay-container">
                    <div className="overlay">
                        <div className="overlay-panel overlay-left">
                            <h1 className='formHeader'>Welcome Back!</h1>
                            <h5>Log in and to get your deals closed faster</h5>
                            <button className="ghost" ref={signInButtonRef}>Sign In</button>
                        </div>
                        <div className="overlay-panel overlay-right">
                            <h1 className='formHeader'>Hey There!</h1>
                            <h5 className='regP'>Signing up with us is simple and takes less than a minute</h5>
                            <button className="ghost" ref={signUpButtonRef}>Sign Up</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    )
}

export default SignInPage;

方式二:使用状态控制类名(推荐)

通过React状态管理UI状态,动态控制容器类名,完全遵循声明式编程模式:

import React, { useContext, useState } from 'react';
import { AlertBoxContext } from '../contexts/alertbox-context';
import { AuthContext } from '../contexts/auth-context';

import '../scss/pages/NewSignup.scss'


function SignInPage() {
    const { SignUp } = useContext(AuthContext);
    const { showAlertBox } = useContext(AlertBoxContext);

    // 用状态标记右侧面板是否激活
    const [isRightPanelActive, setIsRightPanelActive] = useState(false);

    const handleSignUpClick = () => {
        setIsRightPanelActive(true);
    };

    const handleSignInClick = () => {
        setIsRightPanelActive(false);
    };

    return (
        <div className='pageBackground'>
            {/* 根据状态动态添加类名 */}
            <div className={`loginContainer ${isRightPanelActive ? 'right-panel-active' : ''}`}>
                <div className="regForm-container sign-up-container">
                    <form className='regForm' action="/">
                        <h1 className='formHeader'>Create Account</h1>
                        <input type="text" placeholder="Name" />
                        <input type="email" placeholder="Email" />
                        <input type="password" placeholder="Password" />
                        <button className='formBtn'>Sign Up</button>
                    </form>
                </div>
                <div className="regForm-container sign-in-container">
                    <form className='regForm' action="/">
                        <h1 className='formHeader'>Log in</h1>
                        <input type="email" placeholder="Email" />
                        <input type="password" placeholder="Password" />
                        <h5 className='forgotPass' href="/">Forgot your password?</h5>
                        <button className='formBtn'>Log In</button>
                    </form>
                </div>
                <div className="overlay-container">
                    <div className="overlay">
                        <div className="overlay-panel overlay-left">
                            <h1 className='formHeader'>Welcome Back!</h1>
                            <h5>Log in and to get your deals closed faster</h5>
                            {/* 直接绑定点击事件 */}
                            <button className="ghost" onClick={handleSignInClick}>Sign In</button>
                        </div>
                        <div className="overlay-panel overlay-right">
                            <h1 className='formHeader'>Hey There!</h1>
                            <h5 className='regP'>Signing up with us is simple and takes less than a minute</h5>
                            {/* 直接绑定点击事件 */}
                            <button className="ghost" onClick={handleSignUpClick}>Sign Up</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    )
}

export default SignInPage;

说明

  • 方式一适合必须直接操作DOM的场景(如集成第三方UI库),但需注意清理事件监听避免内存泄漏。
  • 方式二是React推荐的写法,通过状态变化驱动UI更新,代码更易维护、更符合React设计理念。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 10:33:47