【问题标题】:React Native - How to submit a Formik from HeaderReact Native - 如何从 Header 提交 Formik
【发布时间】:2021-05-31 03:39:32
【问题描述】:

我是 Formik 和 React Native 的新手。目前,我的目标是通过 Navigation 标头提交表单。我发现的所有示例都是从屏幕页面本身提交表单。我需要帮助弄清楚如何正确使用 handleSubmitonSubmit 属性以及 setParams 将值正确传递给导航标题。

现在,我无法将表单中的值发送到 useCallBack 挂钩。

import React, {useState, useEffect, useCallback} from 'react';
import {StyleSheet, View, Button, Text} from 'react-native';
import {Input} from 'react-native-elements';
import {useDispatch} from 'react-redux';
import Colors from '../../constants/Colors';
import {
  HeaderButtons,
  HeaderButton,
  Item,
} from 'react-navigation-header-buttons';
import {Ionicons} from '@expo/vector-icons';
import {CommonActions} from '@react-navigation/native';
import * as prodActions from '../../store/actions/products';
import {Formik} from 'formik';
import * as Yup from 'yup';

const AddProduct = ({navigation}) => {

  const dispatch = useDispatch();

  const submitHandler = useCallback(() => {
    dispatch(prodActions.addProduct(value));
  }, [value]);

  useEffect(() => {
    navigation.dispatch(CommonActions.setParams({submitForm: submitHandler}));
  }, [submitHandler]);

  return (
    <View style={styles.screen}>
      <Formik
        initialValues={{title: '', description: '', imageUrl: ''}}
        validationSchema={Yup.object({
          title: Yup.string().required('please input your title'),
          description: Yup.string().required('please input your description'),
          imageUrl: Yup.string()
            //.email('Please input a valid email.')
            .required('Please input an email address.'),
        })}
        onSubmit={submitHandler}
      >
        {({
          handleChange,
          handleBlur,
          handleSubmit,
          values,
          touched,
          errors,
        }) => (
          <View>
            <Input
              label="Title"
              labelStyle={{color: Colors.accent}}
              onChangeText={handleChange('title')}
              onBlur={handleBlur('title')}
              value={values.title}
              // errorMessage={errors.title}
            />
            {touched.title && errors.title ? (
              <Text style={styles.error}>{errors.title}</Text>
            ) : null}
            <Input
              label="Description"
              labelStyle={{color: Colors.accent}}
              onChangeText={handleChange('description')}
              onBlur={handleBlur('description')}
              value={values.description}
            />
            {touched.description && errors.description ? (
              <Text style={styles.error}>{errors.description}</Text>
            ) : null}
            <Input
              label="Image URL"
              labelStyle={{color: Colors.accent}}
              onChangeText={handleChange('imageUrl')}
              onBlur={handleBlur('imageUrl')}
              value={values.imageUrl}
            />
            {touched.imageUrl && errors.imageUrl ? (
              <Text style={styles.error}>{errors.imageUrl}</Text>
            ) : null}
            <Button onPress={handleSubmit} title="Submit" />
          </View>
        )}
      </Formik>
    </View>
  );
};

const IoniconsHeaderButton = (props) => (
  <HeaderButton
    IconComponent={Ionicons}
    iconSize={23}
    color="white"
    {...props}
  />
);

export const AddProductHeaderOptions = (navData) => {
  const updateForm = navData.route.params.submitForm;
  return {
    headerRight: () => {
      return (
        <HeaderButtons HeaderButtonComponent={IoniconsHeaderButton}>
          <Item title="add" iconName="save-outline" onPress={updateForm} />
        </HeaderButtons>
      );
    },
  };
};

export default AddProduct;

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    marginHorizontal: 20,
    marginTop: 20,
  },
  error: {
    marginLeft: 8,
    fontSize: 14,
    color: 'red',
  },
});

【问题讨论】:

  • const submitHandler = useCallback( ({values}) =&gt; { ... }, [] ); ... 没有依赖,因为值不在此范围内

标签: react-native formik use-effect usecallback


【解决方案1】:

您可能正在使用具有空值的“值”变量。您必须在 中引用所有表单数据,例如:

value={values.street}
error={touched.street && !isSubmitting && errors.street}
returnKeyType="next"
onSubmitEditing={() => refs.number.current?.focus()}
ref={refs.street}

所以先声明这个 ref 变量:

const refs = {
street: useRef<any>(null),
number: useRef<any>(null),
zipCode: useRef<any>(null),
//....

如果您不想使用 REF,那么至少声明变量并尝试一下,就像这样:

const [value, setValue] = useState();

此外,VALUE 名称不是一个好的变量名称,因为有很多本机的东西使用它。但是,考虑到您一定是从示例中获取的,请将 useState 与您的表单或对象一起使用,您应该会很好。

const [formx, setFormx] = useState();

【讨论】:

    【解决方案2】:

    对于那些使用 React-Navigation 5 和 Formik 1.5.x+ 的人来说,这是一个很好的解决方案。 在函数组件的外部/内部声明一个 ref 变量,以便稍后附加到您的

    let formRef;//or you can use const formRef = useRef(); inside function component
    

    如果你在你的函数组件之外声明 formRef 使用 React hook {useRef} 来更新 ref

    formRef = useRef();
    

    渲染

    <Formik innerRef={formRef} />
    

    最后在你的标题按钮中调用这个

    navigation.setOptions({
    headerRight: () => (
        <Button onPress={() => {
            if (formRef.current) {
               formRef.current.handleSubmit()
            }
        }}/>
      )
    });
    

    【讨论】:

      【解决方案3】:

      另一个我认为可能更好的解决方案是使用 useFormik,它使您可以访问所有表单处理程序和表单元:

        const {
          handleSubmit,
          handleChange,
          isValid,
        } = useFormik({
          initialValues: {...},
          validationSchema: yupValidationSchema,
          onSubmit: (formValues) => {
            //save here...
          }
        });
      

      然后您可以使用官方文档中建议的 useLayoutEffect 将 handleSubmit 引用简单地传递给您的右侧标题导航:

      useLayoutEffect(() => {
        navigation.setOptions({
          headerRight: () => {
            return (
              <HeaderButtons HeaderButtonComponent={IoniconsHeaderButton}>
                <Item title="add" iconName="save-outline" onPress={handleSubmit}/>
             </HeaderButtons>
          );
        }
      });
      

      });

      我认为这种方法很清楚,因为您不需要处理使用 renderProps 方法的所有结构性缺点

      <Formkik>
        {({ handleSubmit }) => (
         jsx here...
        )}
      </Formik>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-06
        • 1970-01-01
        • 1970-01-01
        • 2021-08-15
        • 2019-10-04
        • 1970-01-01
        • 2020-08-23
        相关资源
        最近更新 更多