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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:45:29