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

当React组件传入的props变化时,持久化Formik表单输入值

解决Formik子组件因props更新丢失输入内容的问题

核心问题原因

你遇到的问题本质是:当直接将父组件传递的props作为Formik的initialValues时,每次props更新都会触发Formik重置初始值,导致用户已输入的内容被覆盖。同时父组件其他事件触发的重渲染,如果子组件没有做优化,也会跟着重渲染,加重这个问题。

具体解决方案

1. 分离初始值与动态props,仅首次渲染设置初始值

只在组件第一次挂载时用props初始化表单,后续props变化不再重置已输入内容。可以用useRef标记首次渲染,配合useEffect控制逻辑:

import { useFormik } from 'formik';
import { useEffect, useRef } from 'react';

const ChildForm = ({ options }) => {
  const isFirstRender = useRef(true);
  const formik = useFormik({
    initialValues: { selectedOption: options[0]?.value || '' },
    onSubmit: (values) => {
      console.log('提交内容:', values);
    },
  });

  useEffect(() => {
    // 仅首次渲染后完成初始化标记,后续props变化不重置表单
    if (isFirstRender.current) {
      isFirstRender.current = false;
      return;
    }
    // 若需要根据新props更新可选选项(而非重置输入),可在这里处理下拉框选项更新
  }, [options]);

  return (
    <form onSubmit={formik.handleSubmit}>
      <select
        name="selectedOption"
        value={formik.values.selectedOption}
        onChange={formik.handleChange}
      >
        {options.map(opt => (
          <option key={opt.value} value={opt.value}>{opt.label}</option>
        ))}
      </select>
      <button type="submit">提交</button>
    </form>
  );
};

2. 谨慎使用enableReinitialize属性

如果确实需要在特定场景下重置表单,可使用Formik的enableReinitialize,但不要直接设为true,而是通过一个控制变量决定是否重置:

const ChildForm = ({ options, shouldResetForm }) => {
  const formik = useFormik({
    initialValues: { selectedOption: options[0]?.value || '' },
    enableReinitialize: shouldResetForm, // 仅当需要重置时开启
    onSubmit: (values) => {
      console.log('提交内容:', values);
    },
  });

  // 表单结构同上
};

父组件中仅在需要重置表单的事件触发时,将shouldResetForm设为true,完成后再设回false。

3. 优化子组件渲染,避免不必要重渲染

用React.memo包裹子组件,同时父组件中用useMemo缓存引用类型的props(比如options数组),确保只有当props真正变化时子组件才重渲染:

// 父组件
import { useState, useMemo } from 'react';
import ChildForm from './ChildForm';

const ParentComponent = () => {
  const [otherState, setOtherState] = useState(false);
  
  // 用useMemo缓存options,避免父组件其他状态变化时生成新的数组引用
  const options = useMemo(() => [
    { value: '1', label: '选项1' },
    { value: '2', label: '选项2' },
  ], []);

  return (
    <div>
      <button onClick={() => setOtherState(!otherState)}>触发其他事件</button>
      <ChildForm options={options} />
    </div>
  );
};

// 子组件
import { useFormik } from 'formik';
import React from 'react';

const ChildForm = React.memo(({ options }) => {
  const formik = useFormik({
    initialValues: { selectedOption: options[0]?.value || '' },
    onSubmit: (values) => {
      console.log('提交内容:', values);
    },
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <select
        name="selectedOption"
        value={formik.values.selectedOption}
        onChange={formik.handleChange}
      >
        {options.map(opt => (
          <option key={opt.value} value={opt.value}>{opt.label}</option>
        ))}
      </select>
      <button type="submit">提交</button>
    </form>
  );
});

内容的提问来源于stack exchange,提问作者Karim SOUARI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:35:13