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

React+Chakra UI输入框打字失焦,自定义提交按钮场景求修复

修复React输入框打字时失去焦点的问题(Chakra UI + 自定义按钮场景)

问题根源

你把SubmitButton组件定义在了Login组件内部,每次输入内容触发setFormData更新state时,Login组件会重新渲染,此时会重新创建一个全新的SubmitButton组件实例。React会判定这个新组件和之前的不是同一个元素,销毁旧按钮并挂载新按钮,这个DOM替换操作会导致父容器重渲染,连带输入框失去焦点。


修复方案

方案1:将SubmitButton移到Login组件外部(推荐)

把自定义按钮组件提取到父组件外部,通过props传递需要的状态值,这样它就不会随Login的每次重渲染而被重新创建:

import React, { useState } from "react";
import { Input, Button } from "@chakra-ui/react"; // 补上Button的导入

// 移到Login外部,通过props接收状态
function SubmitButton({ email, password, isLoading }) {
  if (email && password.length > 7) {
    return (
      <Button
        type="submit"
        isLoading={isLoading}
      >
        Login to your account
      </Button>
    );
  } else {
    return (
      <Button
        type="submit"
        isDisabled
      >
        Login to your account
      </Button>
    );
  }
}

const Login = () => {
  const [formData, setFormData] = useState({
    email: "",
    password: "",
  });
  const [isLoading, setIsLoading] = useState(false); // 补上缺失的isLoading状态
  const { email, password } = formData;

  const onChange = (e) => {
    setFormData((prevState) => ({
      ...prevState,
      [e.target.name]: e.target.value,
    }));
  };

  return (
    <div>
      <Input
        name="email"
        value={email}
        onChange={onChange}
      />
      <Input
        value={password}
        name="password"
        onChange={onChange}
      />
      {/* 传递需要的props */}
      <SubmitButton email={email} password={password} isLoading={isLoading} />
    </div>
  )
}

export default Login

方案2:用React.memo包裹内部定义的SubmitButton

如果必须把SubmitButton留在Login内部,可以用React.memo包裹它,让React只有在props变化时才重新渲染这个组件,避免不必要的实例重建:

import React, { useState, memo } from "react";
import { Input, Button } from "@chakra-ui/react"; // 补上Button的导入

const Login = () => {
  const [formData, setFormData] = useState({
    email: "",
    password: "",
  });
  const [isLoading, setIsLoading] = useState(false); // 补上缺失的isLoading状态
  const { email, password } = formData;

  const onChange = (e) => {
    setFormData((prevState) => ({
      ...prevState,
      [e.target.name]: e.target.value,
    }));
  };

  // 用memo包裹,仅当props变化时重渲染
  const SubmitButton = memo(({ email, password, isLoading }) => {
    if (email && password.length > 7) {
      return (
        <Button
          type="submit"
          isLoading={isLoading}
        >
          Login to your account
        </Button>
      );
    } else {
      return (
        <Button
          type="submit"
          isDisabled
        >
          Login to your account
        </Button>
      );
    }
  });

  return (
    <div>
      <Input
        name="email"
        value={email}
        onChange={onChange}
      />
      <Input
        value={password}
        name="password"
        onChange={onChange}
      />
      <SubmitButton email={email} password={password} isLoading={isLoading} />
    </div>
  )
}

export default Login

额外注意点

  1. 原代码中缺失Button的导入,需要从@chakra-ui/react中一起导入
  2. 原代码里isLoading状态未定义,需要补充对应的useState声明

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:37:30