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

React组件在Chrome标签切换/最小化时重渲染致表单异常求助

问题分析与修复方案

核心问题1:Reducer中的属性名错误

你的emailReducer和passwordReducer在处理Input_Blur动作时,错误引用了state.val(初始state的属性是value,不是val),导致输入框的值被覆盖为undefined,进而触发校验失败,切换标签页时组件重新渲染就会暴露这个问题,甚至引发崩溃。

核心问题2:同步更新formIsValid的时机错误

在输入框的onChange处理函数中,dispatch更新state后立即读取emailState.isValid/passwordState.isValid,此时reducer的state还未完成更新,你拿到的是旧状态,导致formIsValid被设置为错误值,同时和监听emailIsValid/passwordIsValid的useEffect重复执行,引发不必要的重渲染。


修复后的完整代码

import React, { useEffect, useState, useReducer } from "react";

import Card from "../UI/Card/Card";
import classes from "./Login.module.css";
import Button from "../UI/Button/Button";

const Login = (props) => {
  console.log("Login Component Re-renders");
  const [formIsValid, setFormIsValid] = useState();

  const emailReducer = (state, action) => {
    if (action.type === "User_Input") {
      return { value: action.val, isValid: action.val.includes("@") };
    }
    if (action.type === "Input_Blur") {
      // 修复:将state.val改为state.value
      return { value: state.value, isValid: state.value.includes("@") };
    }
    return { value: "", isValid: false };
  };

  const [emailState, dispatchEmail] = useReducer(emailReducer, {
    value: "",
    isValid: null,
  });

  const passwordReducer = (state, action) => {
    if (action.type === "User_Input") {
      return { value: action.val, isValid: action.val.trim().length > 6 };
    }
    if (action.type === "Input_Blur") {
      // 修复:将state.val改为state.value
      return { value: state.value, isValid: state.value?.trim().length > 6 };
    }
    return { value: "", isValid: false };
  };

  const [passwordState, dispatchPassword] = useReducer(passwordReducer, {
    value: "",
    isValid: null,
  });

  const { isValid: emailIsValid } = emailState;
  const { isValid: passwordIsValid } = passwordState;

  useEffect(() => {
    const identifier = setTimeout(() => {
      console.log("Checking Form Validity");
      setFormIsValid(emailIsValid && passwordIsValid);
    }, 1000);
    return () => {
      console.log("Clean Up");
      clearTimeout(identifier);
    };
  }, [emailIsValid, passwordIsValid]);

  const emailChangeHandler = (event) => {
    dispatchEmail({ type: "User_Input", val: event.target.value });
    // 移除:这里不再同步更新formIsValid,交给useEffect处理
  };

  const validateEmailHandler = () => {
    dispatchEmail({ type: "Input_Blur" });
  };

  const passwordChangeHandler = (event) => {
    dispatchPassword({ type: "User_Input", val: event.target.value });
    // 移除:这里不再同步更新formIsValid,交给useEffect处理
  };

  const validatePasswordHandler = () => {
    dispatchPassword({ type: "Input_Blur" });
  };

  const submitHandler = (event) => {
    event.preventDefault();
    props.onLogin(emailState.value, passwordState.value);
  };

  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <div
          className={`${classes.control} ${
            emailState.isValid === false ? classes.invalid : ""
          }`}
        >
          <label htmlFor="email">E-Mail</label>
          <input
            type="email"
            id="email"
            value={emailState.value}
            onChange={emailChangeHandler}
            onBlur={validateEmailHandler}
          />
        </div>
        <div
          className={`${classes.control} ${
            passwordState.isValid === false ? classes.invalid : ""
          }`}
        >
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            value={passwordState.value}
            onChange={passwordChangeHandler}
            onBlur={validatePasswordHandler}
          />
        </div>
        <div className={classes.actions}>
          <Button type="submit" className={classes.btn} disabled={!formIsValid}>
            Login
          </Button>
        </div>
      </form>
    </Card>
  );
};

export default Login;

修复说明

  1. 修正Reducer属性名:把两个reducer中Input_Blur分支的state.val改为state.value,确保输入框的值不会被错误覆盖为undefined。
  2. 移除同步更新formIsValid的代码:onChange处理函数中不再手动调用setFormIsValid,完全交给监听emailIsValid和passwordIsValid的useEffect去处理,避免使用旧状态更新表单有效性,同时减少不必要的重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 15:37:01