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

使用Formik FieldArray时输入框重渲染导致输入失焦问题咨询

问题说明

在Formik中使用FieldArray时,每次在输入框输入内容都会触发全列表重渲染,直接导致输入过程中焦点丢失,核心复现代码如下:

<FieldArray
  name="wallets"
  className="space-y-4"
  component={(arrayHelpers) => (
    <>
      {
        formik.values.wallets.map((wallet, i) => (
          <div
            key={i}
            {...}

该场景下wallet对象不存在可作为key的不可变值(所有业务字段均支持在表单内编辑),且重渲染根源不是索引作为key的问题,是Formik值更新时会全量重渲染map生成的所有列表项,以下是无侵入性hack的可行解决方案。

解决方案
  • 抽离独立列表项组件+React.memo优化
    不要将单条wallet项的渲染逻辑直接写在FieldArray的component/render回调中,将单条列表项抽离为独立组件,仅传入当前项索引、字段前缀两个必要props,用React.memo包裹组件做浅比较。只要props不发生变化,组件就不会因为父级(FieldArray回调)重渲染而跟着重渲染。注意不要将整个formik实例、整个wallets数组传入子组件,否则会导致浅比较失效。
  • 列表项内用useField/FastField做字段绑定
    抽离后的子组件中,不要依赖外层map传入的wallet对象绑定输入值,而是通过useField(wallets.${index}.fieldName)的方式绑定对应字段,或者直接使用FastField组件渲染输入控件。FastField内置了浅比较逻辑,仅当自身绑定的字段值、errors、touched状态变化时才会触发重渲染,不会被其他字段更新、数组整体状态变化影响。
  • 给数组项增加临时稳定标识作为key
    初始化wallets数组、新增数组项时,给每个项增加一个不会被表单编辑的_uid字段,值用crypto.randomUUID()生成即可,该字段仅作为React渲染用的key,不参与业务逻辑,提交表单前过滤掉该字段即可。该方案完全不侵入原有业务字段逻辑,可以从根源避免React因为key不稳定导致的DOM卸载重建,配合前两个优化点可以彻底解决焦点丢失问题。

核心注意点:不要在FieldArray的render/component回调中直接写内联的输入控件渲染逻辑。Formik上下文每次状态更新都会全量执行该回调,内联定义的函数、组件每次渲染都是全新引用,React会判定所有子节点需要重渲染,这才是全列表重渲染的核心诱因,和索引作为key的关联度极低。

内容的提问来源于stack exchange,提问作者Toni Bardina Comas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:06:18