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
额外注意点
- 原代码中缺失
Button的导入,需要从@chakra-ui/react中一起导入 - 原代码里
isLoading状态未定义,需要补充对应的useState声明
内容的提问来源于stack exchange,提问作者Noob
相关产品推荐
相关产品推荐

