【问题标题】:Clearing Formik errors and form data - React Native清除 Formik 错误和表单数据 - React Native
【发布时间】:2022-10-22 21:02:45
【问题描述】:

我正在使用 Formik,想知道如何在离开屏幕时清除错误和表单值。

例如,用户尝试提交没有值的表单并显示错误:

当用户然后导航到不同的屏幕然后返回时,这些错误仍然存​​在。有没有办法清除这些?例如,我可以在 useEffect 挂钩中访问 Formik 方法吗?

到目前为止,这是我的实现:

export const SignIn = ({route, navigation}) => {

  const formValidationSchema = Yup.object().shape({
    signInEmail: Yup.string()
      .required('Email address is required')
      .email('Please provide a valid email address')
      .label('Email'),
     signInPassword: Yup.string()
      .required('Password is required')
      .label('Password'),
  });

  const initialFormValues = {
    signInEmail: '',
    signInPassword: '',
  };

  return (
    <Formik
      initialValues={initialFormValues}
      validationSchema={formValidationSchema}
      onSubmit={(values, formikActions) => {
      handleFormSubmit(values);
    }}>
    {({handleChange, handleSubmit, errors}) => (
      <>
        <SignInForm
          messages={errors}
          navigation={navigation}
          handleFormSubmit={handleSubmit}
        />
      </>
    )}
   </Formik>
  )

}

【问题讨论】:

    标签: react-native formik


    【解决方案1】:

    这里的问题是,如果我们导航到不同的屏幕,则不会卸载屏幕,并且 Formik 表单的初始值只会在屏幕安装时设置。

    我创建了一个包含一个字段的最小示例,每当submit 按钮被执行到Stack.Navigator 中的不同屏幕时,我都会导航。 请注意,如果表单字段中有错误,通常不会触发 onSubmit 函数。但是,由于我想提供一个快速测试,我通过直接调用该函数来手动导航。

    如果我们通过按下导航器的onBack 按钮进行导航,表单字段将重置为默认值,所有错误将自动重置。

    我们可以使用Formik innerRef propfocus listener 手动触发。

    为了对此进行测试,您应该执行以下操作。

    1. 键入一些内容,然后将其删除。请注意输入字段下方呈现的错误消息。
    2. 使用提交按钮导航到屏幕。
    3. 回去吧。
    4. 预期结果:没有错误消息。
    5. 输入一些东西。预期结果:没有错误消息。
    6. 提交时导航。
    7. 回去吧。
    8. 预期结果:没有错误消息,字段中没有内容。

      原则上,这将适用于每个导航器,例如更改 Tab.Navigator 中的选项卡,它将重置错误和字段的内容。

      关键部分由以下代码sn-p给出。

      const ref = useRef(null)
        const initialFormValues = {
          signInEmail: '',
          signInPassword: '',
        };
      
        React.useEffect(() => {
          const unsubscribe = navigation.addListener('focus', () => {
            if (ref?.current) {
              ref.current.values = initialFormValues
              ref.current.setErrors({})
              console.log(ref.current)
            }
          });
          return unsubscribe;
        }, [navigation, initialFormValues]);
      
      return (
          <Formik
            innerRef={ref}
            isInitialValid={true}
            initialValues={initialFormValues}
            validationSchema={formValidationSchema}
            onSubmit={(values) => {
                console.log("whatever")
          }}>
      
      ...
      

      完整代码如下。

      import React, { useRef} from 'react';
      
      import { StyleSheet, Text, View,TextInput, Button } from 'react-native';
      import { NavigationContainer } from '@react-navigation/native';
      import { createNativeStackNavigator } from '@react-navigation/native-stack';
      import { Formik } from 'formik';
      
      import * as Yup from 'yup';
      
      
      export const SignIn = ({route, navigation}) => {
      
        const formValidationSchema = Yup.object().shape({
          signInEmail: Yup.string()
            .required('Email address is required')
            .label('Email'),
        });
      
        const ref = useRef(null)
        const initialFormValues = {
          signInEmail: '',
          signInPassword: '',
        };
      
        React.useEffect(() => {
          const unsubscribe = navigation.addListener('focus', () => {
            if (ref?.current) {
              ref.current.values = initialFormValues
              ref.current.setErrors({})
              console.log(ref.current)
            }
          });
          return unsubscribe;
        }, [navigation, initialFormValues]);
      
      
        function handleFormSubmit(values) {
          navigation.navigate("SomeScreen")
        }
      
        return (
          <Formik
            innerRef={ref}
            isInitialValid={true}
            initialValues={initialFormValues}
            validationSchema={formValidationSchema}
            onSubmit={(values) => {
                console.log("whatever")
          }}>
          {({handleChange, handleSubmit, errors, values}) => (
            <>
              <View>
               <TextInput
                 style={{height: 30}}
                 placeholder={"Placeholder mail"}
                 onChangeText={handleChange('signInEmail')}
                 value={values.signInEmail}
               />
               {errors.signInEmail ?
                  <Text style={{ fontSize: 10, color: 'red' }}>{errors.signInEmail}</Text> : null
               }
               <Button onPress={() => {
                 handleSubmit()
                 handleFormSubmit()}} title="Submit" />
             </View>
            </>
          )}
         </Formik>
        )
      
      }
      
      export function SomeOtherScreen(props) {
        return <></>
      } 
      
      const Stack = createNativeStackNavigator();
      
      export default function App() {
          return (
              <NavigationContainer>
                  <Stack.Navigator>
                    <Stack.Screen name="Form" component={SignIn} />
                    <Stack.Screen name="SomeScreen" component={SomeOtherScreen} />
                  </Stack.Navigator>
              </NavigationContainer>
          );
      }
      
      const styles = StyleSheet.create({
          container: {
              flex: 1,
              backgroundColor: '#fff',
              alignItems: 'center',
              justifyContent: 'center',
          },
      });
      

    【讨论】:

    • 为延迟回复道歉,只是再次关注这个问题,你的回答帮助很大,学到了很多关于 useRef 的知识。谢谢你
    【解决方案2】:

    这应该可以通过反应导航中的 useFocusEffect 钩子实现。它会在第一次和每次屏幕聚焦时触发。

    useFocusEffect(
        React.useCallback(() => {
          // set Formik Errors to empty object
          setErrors({});
          // Since your clearing errors, you should also reset the formik values
          setSignInEmail('');
          setSignInPassword('');
    
          return () => {}; // gets called on unfocus. I don't think you need this
        }, [])
      );
    

    【讨论】:

    • setErrors 在我尝试这个时没有定义
    • 我从不需要使用 formik 删除错误,我只是快速搜索了一下,他们说 setErrors({});也许你必须从 formik 或一些 idk 导入它。你有 14k 的声望,所以我相信你会弄清楚的 :)。这是可能的,这个问题的主要部分是 useFocusEffect。对不起,我不能再帮你了。
    猜你喜欢
    • 2019-06-06
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 1970-01-01
    • 2019-10-04
    相关资源
    最近更新 更多