
当使用 包裹受控输入组件并点击 type="submit" 按钮时,若未阻止默认提交行为,页面会刷新或重渲染,导致输入框意外失焦。根本原因在于缺少 e.preventDefault() 和正确的表单事件绑定。
当使用 `
import { Button, Input, FormControl, FormLabel } from "@chakra-ui/react";
import React, { useState } from "react";
export default function Login() {
const [formData, setFormData] = useState({ email: "", password: "" });
const [isLoading, setIsLoading] = useState(false);
const { email, password } = formData;
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData((prev) => ({
...prev,
[e.target.name]: e.target.value,
}));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); // ✅ 关键:阻止页面刷新/重载
console.log("Form submitted:", { email, password });
setIsLoading(true);
try {
// 模拟 API 调用(如 userLogin)
await new Promise(resolve => setTimeout(resolve, 1500));
// 登录成功逻辑:跳转、存储 token 等
} catch (err) {
console.error("Login failed", err);
} finally {
setIsLoading(false);
}
};
const SubmitButton = () => (
<Button
type="submit"
mt={4}
isLoading={isLoading}
loadingText="Signing in"
isDisabled={!email || password.length < 8}
width="full"
>
Login to your account
</Button>
);
return (
<form onSubmit={handleSubmit}> {/* ✅ 必须包裹 form 标签并绑定 onSubmit */}
<FormControl isRequired mb={4}>
<FormLabel>Email</FormLabel>
<Input
name="email"
type="email"
placeholder="Enter your email"
value={email}
onChange={handleChange}
/>
</FormControl>
<FormControl isRequired mb={6}>
<FormLabel>Password</FormLabel>
<Input
name="password"
type="password"
placeholder="Enter password (min. 8 chars)"
value={password}
onChange={handleChange}
/>
</FormControl>
<SubmitButton />
</form>
);
}⚠️ 常见错误与注意事项
-
错误模式:直接在 div 中放置 type="submit" 按钮(如原始代码)→ 浏览器找不到所属
,部分环境会向上冒泡至最近 或触发全局提交,造成不可预测失焦; - 状态更新时机:确保 onChange 使用函数式更新(setFormData(prev => {...})),避免因异步渲染导致状态滞后;
- 禁用按钮逻辑:推荐将 isDisabled 条件统一放在按钮层(而非条件渲染不同
-
Chakra 特性提示:
和 不仅增强语义化,还能配合 isInvalid / errorBorderColor 实现错误反馈,但不替代 e.preventDefault() 的必要性。
总结
输入框失焦的本质是表单未被正确控制。解决它不依赖于替换 Button 组件,而在于补全 React 表单的黄金三角:
✅ 受控组件(value + onChange)
✅
✅ handleSubmit(e) 中调用 e.preventDefault()
只要三者齐备,无论使用 Chakra、Mantine 还是原生 HTML,都能稳定保持输入焦点,为用户提供流畅的交互体验。









