在react-hook-form中用一个handleSubmit提交并处理两个表单

Nim*_*ima 5 javascript forms reactjs react-native react-hook-form

在我的反应应用程序中,我在一页上有两个地址表单,它们有两个保存地址函数,可将地址保存在数据库中。还有一个提交按钮,可以提交两个字段并导航到下一页(圆圈中的加号按钮将地址添加到已保存的地址列表中):

在此输入图像描述

我想要做的是验证表单字段,并且我已经通过调用挂钩的两个实例来做到这一点useForm()

// useForm hook
  const {
    control: senderControl,
    handleSubmit: handleSenderSubmit,
    setValue: senderSetValue,
  } = useForm({
    defaultValues: {
      senderName: '',
      senderLastName: '',
      senderPostalCode: '',
      senderPhone: '',
      senderAddress: '',
    },
  });

  // useForm hook
  const {
    control: receiverControl,
    handleSubmit: handleReceiverSubmit,
    setValue: receiverSetValue,
  } = useForm({
    defaultValues: {
      receiverName: '',
      receiverLastName: '',
      receiverPhone: '',
      receiverPostalCode: '',
      receiverAddress: '',
    },
  });
Run Code Online (Sandbox Code Playgroud)

然后,我将这两个钩子的 handleSubmit 方法分别添加到每个字段的加号按钮的onClick (onPress在 RN 中)。

这确实单独验证了表单,但是当我尝试使用“提交”按钮提交整个页面时,问题就出现了。

我仍然希望在按下常规“提交”按钮时能够验证这两个地址字段,但我不知道如何用一个实例验证这两个实例handleSubmit并获取return data两个字段的值。

编辑(CustomInput.js):

const CustomInput = ({
  control,
  name,
  rules = {},
  placeholder,
  secureTextEntry,
  keyboardType,
  maxLength,
  textContentType,
  customStyle,
}) => (
  <Controller
    control={control}
    name={name}
    rules={rules}
    render={({field: {onChange, onBlur, value}, fieldState: {error}}) => (
      <View style={customStyle || styles.container}>
        <TextInput
          value={value}
          onBlur={onBlur}
          onChangeText={onChange}
          placeholder={placeholder}
          keyboardType={keyboardType}
          maxLength={maxLength}
          textContentType={textContentType}
          secureTextEntry={secureTextEntry}
          style={[
            styles.textInput,
            {
              borderColor: !error
                ? GENERAL_COLORS.inputBorder
                : GENERAL_COLORS.error,
            },
          ]}
        />
        {error && <Text style={styles.errMsg}>{error.message || 'error'}</Text>}
      </View>
    )}
  />
);
Run Code Online (Sandbox Code Playgroud)

用法:

<CustomInput
    control={control}
    name="senderPostalCode"
    rules={{
      required: 'Postal Code is Required',
    }}
    placeholder="Postal Code"
    keyboardType="number-pad"
    textContentType="postalCode"
    customStyle={{
      width: '49%',
      marginBottom: hp(1),
    }}
/>
Run Code Online (Sandbox Code Playgroud)

有什么办法可以做到这一点吗?

Nim*_*ima 1

感谢@TalgatSaribayev 的评论引导我找到了这个解决方案。

我不需要为地址字段设置任何特定的验证规则,最后我将发送者和接收者表单分成两个不同的页面。

首先,我必须指出,我没有使用APIpostalCode获取和address字段的输入值,而是使用挂钩来获取最新的值。getValues useWatch

// Watch inputs
const watchedInputs = useWatch({
  control,
  name: ['senderPostalCode', 'senderAddress'],
});
Run Code Online (Sandbox Code Playgroud)

当我将输入值保存getValues在变量中时,我得到了前一个状态而不是最新的状态,解决这个问题的唯一方法是getValues('INPUT_NAME')每当我想获取最新的状态时调用。即使如此,我也需要调用 的实例useWatch而不将其保存在任何变量中以跟踪更改,因为在输入字段中键入根本不会更新getValues。所以最后我决定使用useWatch它的值并将其存储在变量中,并使用它来访问输入字段的值。

/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

正如@TalgatSaribayev 指出的那样,仅创建一个useForm实例就足够了。我所要做的就是创建一个函数,该函数将手动设置错误并在按下保存地址按钮时检查其验证。

// Check if sender postal code input has error
const senderHasError = () => {
  if (!/^\d+$/.test(watchedInputs[0])) {
    setError('senderPostalCode', {
      type: 'pattern',
      message: 'Postal Code must be a number',
    });
    return true;
  }
    
  // Any other rules
  if (YOUR_OWN_RULE) {
    setError('senderPostalCode', {
      type: 'custom',
      message: 'CUSTOM_MESSAGE',
    });
    return true;
  }
    
  // Clear error and return false
  clearErrors('senderPostalCode');
  return false;
};
Run Code Online (Sandbox Code Playgroud)

问题是,即使错误通过了验证,也不会被更新(清除)。就好像无效的输入不会附加onChange事件侦听器来重新验证它一样。onSubmit当您以模式提交表单时,默认会发生一些情况useForm。(https://react-hook-form.com/api/useform

所以我决定使用trigger API来手动触发表单验证并在按下保存地址按钮时useForm监听字段上的更改。postalCode

首先,我创建了一个切换状态来更改触发状态:

// Postal code onSubmit event state
const [triggered, setTriggered] = useState(false);
Run Code Online (Sandbox Code Playgroud)

然后使用in atrigger的 API仅当状态设置为 true 并且输入字段的值已更改时才触发输入验证:useFormuseMemotriggered

// Manually trigger input validation if postal code's onSubmit event is true
useMemo(() => {
  if (triggered) trigger('senderPostalCode');
}, [watchedInputs[0]]);
Run Code Online (Sandbox Code Playgroud)

我假设我使用 API 触发输入字段的方式与的模式在幕后的工作trigger方式相同:当用户通过使用 更改状态按下保存地址按钮时启动触发器。useFormonSubmittriggersetTrigger

// Add address to sender favorites
const handleAddSenderFavAddress = () => {
  // Trigger on the press event
  setTriggered(true);

  // Return if sender postal code input has error
  if (senderHasError()) return;

  // SAVE ADDRESS LOGIC
  ///////////////////////////////
};
Run Code Online (Sandbox Code Playgroud)

useForm除了使用shandleSubmit 函数进行的一般验证之外,这是我设法验证单独输入字段的唯一方法。

我欢迎更多可能带来更好解决方案的答案。