React输入框打字失焦且仅允许输入单个字符问题求助
输入框输入时立即失焦的解决方案
问题场景
父组件CustomerFrm通过FormWizard传递包含子组件的数组FormWizardItems,最终渲染的CustomerOrganizationDataTabContentFrm表单依赖useFormik创建的validation属性。当前遇到输入框输入时立即失焦,仅能输入单个字符的问题。
相关代码片段:
父组件传递组件数组
const FormWizardItems = [ { title: "Organization Data", number: 1, component: () => ( <CustomerOrganizationDataTabContentFrm validation={validation} /> ), } ] return ( <> <FormWizard validation={validation} apiCallResponse={registrationError} breadcrumbTitle="Clientes" breadcrumbItemTitle="Register Customer" cardTitle="Clientes" cardDescription="Register Customer" items={FormWizardItems} /> </> )
FormWizard组件内部处理逻辑
<CardBody> <h4 className="card-title mb-4">{cardTitle}</h4> <div className="wizard clearfix"> <div className="steps clearfix"> <ul> {items.map(item => { return ( <FormWizardNavItem key={item.number} number={item.number} title={item.title} activeTab={activeTab} passedSteps={passedSteps} setActiveTab={setActiveTab} /> ) })} </ul> </div> <div className="content clearfix"> <TabContent activeTab={activeTab} className="body"> {items.map(item => { const Component = item.component return ( <FormWizardContent key={item.number} tabId={item.number} activeTab={activeTab} component={() => ( <Component exampleProp="Hello" /> )} /> ) })} </TabContent> </div> </CardBody>
FormWizardContent组件
import React from "react" import { TabPane } from "reactstrap" export const FormWizardContent = props => { const { tabId, component: Component } = props return ( <TabPane tabId={tabId}> <Component /> </TabPane> ) }
Formik配置
const validation = useFormik({ enableReinitialize: true, initialValues: { BusinessName: "", TradingName: "", EinItin: "", StateEin: "", OtherTaxPayerStateEin: "", CityEin: "", CompanyCategory: "", HeadquarterId: null, IsActive: true, }, validationSchema: Yup.object({ BusinessName: Yup.string() .required("Business Name is required") .min(3, "Business Name should have at minimun of 3 characters") .max(3, "Business Name should have up to 3 characters"), TradingName: Yup.string() .required("Trading Name is required") .min(3, "Trading Name should have at minimun of 3 characters") .max(3, "Trading Name should have up to 3 characters"), }), onSubmit: values => { dispatch(registerRole(values)) }, })
问题原因
每次输入触发组件重新渲染时,FormWizardItems中的匿名函数、FormWizard中包裹组件的匿名函数都会创建新的组件实例。React会将其识别为全新组件,卸载旧组件并挂载新组件,导致输入框失去焦点。
解决方案
方案1:传递组件本身而非匿名函数
1. 修改FormWizardItems定义
将组件和其props分离,避免每次渲染创建新函数:
const FormWizardItems = [ { title: "Organization Data", number: 1, component: CustomerOrganizationDataTabContentFrm, componentProps: { validation } // 单独存放组件所需props } ]
2. 调整FormWizard渲染逻辑
直接使用传入的组件和props,不再额外包裹匿名函数:
<div className="content clearfix"> <TabContent activeTab={activeTab} className="body"> {items.map(item => { const Component = item.component return ( <FormWizardContent key={item.number} tabId={item.number} activeTab={activeTab} component={<Component {...item.componentProps} exampleProp="Hello" />} /> ) })} </TabContent> </div>
3. 更新FormWizardContent组件
直接渲染传入的component元素:
import React from "react" import { TabPane } from "reactstrap" export const FormWizardContent = props => { const { tabId, component } = props return ( <TabPane tabId={tabId}> {component} </TabPane> ) }
方案2:用useCallback缓存组件函数
如果必须以函数形式传递组件,使用useCallback缓存函数,保持引用稳定:
1. 在CustomerFrm中缓存组件函数
import { useCallback } from 'react'; // 缓存组件渲染函数,仅在validation变化时重新创建 const renderOrgDataTab = useCallback(() => { return <CustomerOrganizationDataTabContentFrm validation={validation} /> }, [validation]) const FormWizardItems = [ { title: "Organization Data", number: 1, component: renderOrgDataTab, } ]
2. 调整FormWizard中的渲染
<FormWizardContent key={item.number} tabId={item.number} activeTab={activeTab} component={item.component} />
FormWizardContent保持原有调用方式即可。
核心原理
React通过组件引用的一致性判断是否复用组件实例。保持组件/函数引用稳定,避免每次渲染创建新实例,就能让React复用原有组件,解决输入框失焦问题。
内容的提问来源于stack exchange,提问作者Junior Silva
相关产品推荐
相关产品推荐

