reactjs React-Hook-Form和验证

a64a0gku  于 12个月前  发布在  React
关注(0)|答案(3)|浏览(128)

后台

  • 我想做一个数字输入。
  • 此自定义输入仅接受数字,并有字符长度限制。
  • 将使用react-hook-form。
import React, { useEffect, useState } from "react";

type NumberInputProps = {
    _maxLength?: number;
    name: string;
    className?: string;
    onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
    placeholder?: string;
    value?: string;
};

const NumberInput = ({ _maxLength, className, name, onChange: handleChange, placeholder, value }: NumberInputProps) => {
    const [val, setVal] = useState(value);

    useEffect(() => {
        setVal(value);
    }, [value]);

    const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
        alert("handleInput !");

        let value = e.target.value;
        if (_maxLength && value.length >= _maxLength) {
            value = value.slice(0, _maxLength);
        }
        setVal(value);
        handleChange?.(e);
    };

    const cn = `number-input ${className}`;

    return (
        <input name={name} className={cn} type="number" onInput={handleInput} placeholder={placeholder} value={val} />
    );
};

export default NumberInput;

字符串

问题

正如你所看到的,这个组件是受控组件。但是我不想使用useStateuseEffect,因为它使代码太长。
有没有更简单、更直观的方法?

o7jaxewo

o7jaxewo1#

我看不出使用useEffect()有什么价值。将代码改为:

import React, { useState } from "react";

type NumberInputProps = {
    _maxLength?: number;
    name: string;
    className?: string;
    onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
    placeholder?: string;
    value?: string;
};

const NumberInput = ({ _maxLength, className, name, onChange: handleChange, placeholder, value }: NumberInputProps) => {
    const [val, setVal] = useState(value);

    const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
        let value = e.target.value;
        if (_maxLength && value.length >= _maxLength) {
            value = value.slice(0, _maxLength);
        }
        setVal(value);
        handleChange?.(value);
    };

    const cn = `number-input ${className}`;

    return (
        <input name={name} className={cn} type="number" onInput={handleInput} placeholder={placeholder} value={val} />
    );
};

export default NumberInput;

字符串
注意事项:handleChange()的签名被修改,因为我们现在给它的是value,而不是事件e。你可以给予它e,但是你需要在handleInput()中复制“值截断”逻辑。

ou6hu8tu

ou6hu8tu2#

你正在使用react-hook-form。所以我想不再需要useStates了。我想你可以做一些简单的事情,比如这样(如果你愿意,你也可以创建一个公共组件)。

import { useForm, Controller } from 'react-hook-form';

type FormValues = {
  myNumber: number;
};

const maxLength = 5;

function NumberInput({
  onChange,
  value,
}: {
  onChange: (value: number) => void;
  value: number;
}) {
  return (
    <input
      type="number"
      value={value}
      onChange={(e) => {
        onChange(Number(e.target.value.slice(0, maxLength)));
      }}
    />
  );
}

function App() {
  const { handleSubmit, control } = useForm<FormValues>();

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <Controller
        control={control}
        name="myNumber"
        render={({ field: { onChange, value } }) => (
          <NumberInput onChange={onChange} value={value} />
        )}
      />

      <input type="submit" />
    </form>
  );
}

字符串

qyzbxkaa

qyzbxkaa3#

当使用react-hook-form时,大部分代码都不需要。如果你愿意让生活变得更快更简单,这里有一个使用react-hook-form和prime-react的工作示例。
这两个库可以很好地协同工作,并且有很好的文档说明如何使用它们(有一些额外的css导入模板,使一切看起来很花哨,但这些并不需要)。

import React from "react";
import { useForm, Controller } from "react-hook-form";
import { InputNumber } from "primereact/inputnumber";
import "primereact/resources/themes/saga-blue/theme.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";
import { classNames } from "primereact/utils";

//code from github.com/XYIAN/hook-form-sandbox-js
export const MyForm = () => {
  const { control, handleSubmit, formState } = useForm({
    mode: "onBlur", // Trigger validation onBlur
  });

  const onSubmit = (data) => {
    console.log('on submit hit with data:', data);
    //this is only hit when there is no errors in the fields
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="numberInput">Number Input:</label>
        <Controller
          name="numberInput"
          control={control}
          defaultValue={0}
          rules={{
            validate: (value) => {
              // Custom validation rule to limit input length to 10 characters
              return (
                String(value).length <= 10 ||
                "Input length cannot be greater than 10"
              );
            },
          }}
          render={({ field, fieldState }) => (
            <>
              <InputNumber
                id={field.name}
                inputRef={field.ref}
                value={field.value}
                onBlur={field.onBlur}
                onValueChange={(e) => field.onChange(e)}
                useGrouping={false}
                inputClassName={classNames({ "p-invalid": fieldState.error })}
                showButtons
              />
              {fieldState.invalid && (
                <span className="p-error">{fieldState.error?.message}</span>
              )}
            </>
          )}
        />
      </div>
      <button type="submit" disabled={formState.isSubmitting}>
        Submit
      </button>
    </form>
  );
};

export default MyForm;

字符串
对于仅限于HTML属性的常规输入,逻辑仍然非常类似

相关问题