React Native + Formik:子组件向父组件传递isValid状态延迟一个输入的问题
React Native + Formik:子组件向父组件传递isValid状态延迟一个输入的问题
嘿,这个Formik状态延迟的问题我太熟了!我来给你拆解下原因和解决办法~
问题根源
你遇到的延迟问题,核心原因是Formik的isValid状态更新是异步的——尤其是结合Yup做验证时,验证逻辑是在输入变化后异步执行的。如果你的onInputChange是在输入框的onChange事件里直接调用的,这时候Formik还没完成验证,传递给父组件的自然是上一次的旧状态,就会出现“慢一拍”的情况。
最优解决方案:让父组件直接对接Formik的状态
其实没必要手动在子父组件间传递isValid,Formik本身就提供了非常方便的上下文和状态暴露,直接在父组件里用就好,完全不会有延迟:
步骤1:父组件包裹Formik并直接使用isValid
import { Formik } from 'formik'; import * as Yup from 'yup'; import EditInputs from './EditInputs'; import { Button } from 'react-native'; const EditProfileScreen = ({ userInfo }) => { // 把验证规则移到父组件(或者单独抽成文件,更易维护) const SignupFormSchema = Yup.object().shape({ name: Yup.string().max(20, 'Name has reached character limit'), username: Yup.string() .min(5, 'Username must be at least 5 characters') .max(20, 'Username has reached character limit') .matches(/^[A-Za-z0-9_]+$/, 'Username can only contain letters, numbers, and underscores') .required('A username is required'), bio: Yup.string().max(200, 'Bio has reached character limit'), email: Yup.string().email().required('An email is required'), // 补充你没写完的number字段规则 }); return ( <Formik initialValues={{ name: userInfo.name, username: userInfo.username, bio: userInfo.bio, email: userInfo.email, // 对应number字段的初始值 }} validationSchema={SignupFormSchema} onSubmit={(values) => { // 这里写你的提交逻辑,比如更新用户信息 console.log('提交的用户信息:', values); }} > {({ isValid, handleSubmit }) => ( <> {/* 子组件直接用Formik的上下文,不需要手动传状态 */} <EditInputs /> {/* 提交按钮直接用Formik的isValid控制禁用状态,实时更新 */} <Button title="保存修改" onPress={handleSubmit} disabled={!isValid} style={{ backgroundColor: isValid ? '#2196F3' : '#ccc' }} /> </> )} </Formik> ); };
步骤2:子组件通过Formik上下文获取状态
子组件不用再接收onInputChange,直接用useFormikContext获取Formik的所有状态和方法,代码更简洁:
import { useFormikContext } from 'formik'; import { TextInput, Text, View } from 'react-native'; const EditInputs = () => { const { values, handleChange, errors, touched } = useFormikContext(); return ( <View style={{ gap: 16, padding: 20 }}> {/* 姓名输入框 */} <View> <TextInput value={values.name} onChangeText={handleChange('name')} placeholder="输入你的姓名" style={{ borderBottomWidth: 1, paddingVertical: 8 }} /> {touched.name && errors.name && ( <Text style={{ color: 'red', fontSize: 12, marginTop: 4 }}>{errors.name}</Text> )} </View> {/* 用户名输入框 */} <View> <TextInput value={values.username} onChangeText={handleChange('username')} placeholder="输入用户名" style={{ borderBottomWidth: 1, paddingVertical: 8 }} /> {touched.username && errors.username && ( <Text style={{ color: 'red', fontSize: 12, marginTop: 4 }}>{errors.username}</Text> )} </View> {/* 其他字段(bio、email、number)同理 */} </View> ); };
如果你一定要手动传递状态的备选方案
如果因为某些特殊需求,必须在子组件里把isValid传给父组件,那可以用useEffect监听Formik的isValid变化,确保只有当验证完成、状态更新后再传递:
import { useFormikContext, useEffect } from 'formik'; const EditInputs = ({ userInfo, onInputChange }) => { const { isValid, values } = useFormikContext(); // 当isValid或者表单值变化时,再通知父组件 useEffect(() => { onInputChange(isValid, values); }, [isValid, values, onInputChange]); // 输入框渲染逻辑和上面一样 };
这样就能保证父组件拿到的是最新的isValid状态,不会再延迟。
备注:内容来源于stack exchange,提问作者naechebango
相关产品推荐
相关产品推荐

