React Native中Formik外部提交函数如何获取表单值
React Native 导航栏外部按钮触发 Formik 表单校验提交方案
React Navigation 的 header 渲染层级独立于页面组件,放在 headerRight 里的提交按钮默认处于 Formik 上下文作用域外,无法直接访问 Formik 内部的状态、校验逻辑和提交方法,会出现拿不到实时表单值、无法自动触发校验流程的问题。
下面提供两种可直接落地的实现方案:
方案1:通过 ref 持有 Formik 实例(推荐,灵活度最高)
这个方案不需要改动原有表单结构,通过 Formik 暴露的 innerRef 属性拿到实例对象,直接调用实例上的提交方法即可,提交前会自动执行配置的校验规则,校验通过才会触发提交逻辑。
- 先在组件顶层创建 ref 存储 Formik 实例
const formikRef = React.useRef<any>(null); - 给 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> - 修改导航栏配置逻辑,按钮点击时直接调用 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
相关产品推荐
相关产品推荐

