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

React Native中Formik外部提交函数如何获取表单值

React Native 导航栏外部按钮触发 Formik 表单校验提交方案

React Navigation 的 header 渲染层级独立于页面组件,放在 headerRight 里的提交按钮默认处于 Formik 上下文作用域外,无法直接访问 Formik 内部的状态、校验逻辑和提交方法,会出现拿不到实时表单值、无法自动触发校验流程的问题。
下面提供两种可直接落地的实现方案:

方案1:通过 ref 持有 Formik 实例(推荐,灵活度最高)

这个方案不需要改动原有表单结构,通过 Formik 暴露的 innerRef 属性拿到实例对象,直接调用实例上的提交方法即可,提交前会自动执行配置的校验规则,校验通过才会触发提交逻辑。

  1. 先在组件顶层创建 ref 存储 Formik 实例
    const formikRef = React.useRef<any>(null);
    
  2. 给 Formik 组件绑定 ref,把提交逻辑直接写在 Formik 的 onSubmit 回调中,这里拿到的 values 是校验通过后的最新表单值,不需要额外在外层维护重复的表单状态
    <Formik
      innerRef={formikRef}
      initialValues={initialState}
      validationSchema={getValidationSchema(staticValues.static)}
      onSubmit={async (values) => {
        // 提交逻辑直接写在这里,直接从values取表单字段即可
        const submitData = {
          paymentServiceTypeId: defaultPaymentType,
          invoiceNeeded,
          companyName: values.company,
          vatNumber: values.vatNumber,
        }
        console.log(submitData);
        // 后续接口请求逻辑写在这里
      }}
    >
      {({ handleChange, handleBlur, values, touched, errors, setFieldValue }) => (
        <>
          {/* 原有表单渲染内容保持不变 */}
          {defaultPaymentType == 2 && (
            <>
              <Text style={styles.title}>Company Name</Text>
              <View style={styles.textInputView}>
                <TextInput
                  style={styles.inputText}
                  placeholder={'Company Name'}
                  value={values.company}
                  onChangeText={handleChange('company')}
                  onBlur={handleBlur('company')}
                />
                {touched.company && errors.company && <Text style={styles.errorText}>{errors.company}</Text>}
              </View>
            </>
          )}
        </>
      )}
    </Formik>
    
  3. 修改导航栏配置逻辑,按钮点击时直接调用 Formik 实例的 submitForm 方法,同时把 formikRef 加到 useLayoutEffect 的依赖数组中
    React.useLayoutEffect(() => {
      navigation.setOptions({
        headerTitleAlign: 'center',
        headerTitle: () => <Text style={styles.titleHeader}>Payment Method</Text>,
        headerRight: () => (
          <Pressable onPress={() => formikRef.current?.submitForm()}>
            <Text>Done</Text>
          </Pressable>
        ),
      });
    }, [navigation, userId, formikRef]);
    

方案2:将导航栏配置逻辑移入Formik作用域内

不需要额外维护ref,直接把 useLayoutEffect 写到 Formik 的 render props 回调里,就能直接拿到 Formik 上下文提供的 handleSubmit 方法:

return (
  <Formik
    initialValues={initialState}
    validationSchema={getValidationSchema(staticValues.static)}
    onSubmit={async (values) => {
      // 提交逻辑和方案1一致,直接使用values即可
      const submitData = {
        paymentServiceTypeId: defaultPaymentType,
        invoiceNeeded,
        companyName: values.company,
        vatNumber: values.vatNumber,
      }
      console.log(submitData);
    }}
  >
    {({ handleChange, handleBlur, values, touched, errors, setFieldValue, handleSubmit }) => {
      // 在Formik作用域内设置导航栏,直接拿到内部的handleSubmit
      React.useLayoutEffect(() => {
        navigation.setOptions({
          headerTitleAlign: 'center',
          headerTitle: () => <Text style={styles.titleHeader}>Payment Method</Text>,
          headerRight: () => (
            <Pressable onPress={handleSubmit}>
              <Text>Done</Text>
            </Pressable>
          ),
        });
      }, [navigation, userId, handleSubmit]);

      return (
        <>
          {/* 原有表单渲染内容保持不变 */}
        </>
      )
    }}
  </Formik>
)

注意事项

  • 不要在外层单独维护和Formik重复的表单状态(比如示例代码中外层的company、vatNumber变量),所有表单字段统一交给Formik管理,避免两边状态不同步导致提交数据错误
  • 如果需要实现「表单未填写/校验不通过时Done按钮置灰」的效果,用方案1更方便:直接通过formikRef.current?.isValid、formikRef.current?.dirty等状态控制Pressable的可点击状态即可
  • 两种方案都会在点击按钮时自动执行配置的validationSchema校验,校验不通过会自动展示错误提示,不会触发提交逻辑,完全符合校验后提交的需求

内容的提问来源于stack exchange,提问作者Faizan Ahmad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:18:25