清除formik错误并形成数据 - 反应本机

发布于 2025-01-17 10:07:52 字数 1255 浏览 2 评论 0原文

我正在使用 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>
  )

}

I'm using Formik and was wondering how I go about clearing the errors and form values when leaving a screen.

For example, a user tries to submit the form with no values and the errors are displayed:

enter image description here

When the user then navigates to a different screen and then comes back those errors are still present. Is there a way to clear these? Can I access Formik methods within a useEffect hook as an example?

This is my implementation so far:

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>
  )

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

呆橘 2025-01-24 10:07:52

这里的问题在于,如果我们导航到其他屏幕,并且仅在屏幕上设置了Formik表单的初始值,则不会卸下屏幕。

我已经在一个字段中创建了一个最小的示例,只要将提交按钮执行到stack.navigator中的其他屏幕时,我就会导航。
请注意,如果您的表单字段中存在错误,通常不会触发onsubmit函数。但是,由于我想提供快速测试,因此我通过直接调用该功能来手动导航。

如果我们通过按Navigator的onback按钮来浏览,则表单字段将重置为默认值,所有错误将自动重置。

我们可以使用formik InnerRef Propfocus focus侦听器手工触发此触发。

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

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

总体而言,这将与每个导航器一起使用,例如在标签器中更改选项卡。Navigator,它将重置错误和字段的内容。

关键部分由以下代码段提供。

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',
    },
});

The problem here is that a screen does not get unmounted if we navigate to a different screen and the initial values of a Formik form will only be set on screen mount.

I have created a minimal example with one field and I navigate whenever the submit button is executed to a different Screen in a Stack.Navigator.
Notice that the onSubmit function is usually not fired if there are errors in your form fields. However, since I wanted to provide a quick test, I navigate by hand by calling the function directly.

If we navigate back by pressing the onBack button of the navigator, the form fields will be reseted to the default values and all errors will be reseted automatically.

We can trigger this by hand using the Formik innerRef prop and a focus listener.

For testing this, you should do the following.

  1. Type something, and remove it. Notice the error message that is rendered below the input field.
  2. Navigate to the screen using the submit button.
  3. Go back.
  4. Expected result: no error message.
  5. Type something. Expected result: no error message.
  6. Navigate on submit.
  7. Go back.
  8. Expected result: no error message, no content in field.

In principal, this will work with every navigator, e.g. changing a Tab in a Tab.Navigator and it will reset both, the errors and the field's content.

The key part is given by the following code snippet.

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")
    }}>

...

The full code is given as follows.

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',
    },
});
书间行客 2025-01-24 10:07:52

通过React导航的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
    }, [])
  );

This should be possible with the useFocusEffect hook from react navigation. It gets triggered on first time and every time the screen comes in focus.

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
    }, [])
  );
冷清清 2025-01-24 10:07:52

谢谢Maximilian Dietel。

这对我有用:

 const focusCallback = React.useCallback(() => {
    resetForm();

    return () => {};
  }, []);

  useFocusEffect(focusCallback);

Thank you Maximilian Dietel.

This worked for me:

 const focusCallback = React.useCallback(() => {
    resetForm();

    return () => {};
  }, []);

  useFocusEffect(focusCallback);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文