WoXuS
WoXuS

Reputation: 145

Validating a child input type file with react-hook-form and Yup

I'm creating a form with a file upload with help of react-hook-form and Yup. I am trying to use the register method in my child component. When passing register as a prop (destructured in curly braces) the validation and submiting doesn't work. You can always submit the form and the submitted file object is empty. Here's a sandbox link.

Upvotes: 2

Views: 4148

Answers (1)

Saeed Shamloo
Saeed Shamloo

Reputation: 6564

There are several of problems with your code.

1- register method returns an object with these properties:

{
  onChange: function(){},
  onBlur:function{},
  ref: function(){}
 }

when you define your input like this:

<input
      {...register('photo')}
      ...
      onChange={(event) => /*something*/}
  />

actually you are overrding the onChange method which has returned from register method and react-hook-form couldn't recognize the field change event. The solution to have your own onChange alongside with react-hook-form's onChange could be something like this:

const MyComp = ()=> {
  const {onChange, ...registerParams} = register('photo');
  ...
  return (
    ...
    <input
        {...params}
        ...
        onChange={(event) => {
          // do whatever you want
          onChange(event)
        }}
      />
  );
}

2- When you delete the photo, you are just updating your local state, and you don't update photo field, so react-hook-form doesn't realize any change in your local state.

the problems in your ImageOne component could be solved by change it like this:

function ImageOne({ register, errors }) {
  const [selectedImage, setSelectedImage] = useState(null);
  const { onChange, ...params } = register("photo");
  return (
    ...
    <Button
           className="delete"
           onClick={() => {
              setSelectedImage(null);
              //Make react-hook-form aware of changing photo state
              onChange({ target: { name: "photo", value: [] } });
            }}
          >
         ...
          <input
            //name="photo"
            {...params}
            type="file"
            accept="image/*"
            id="single"
            onChange={(event) => {
              setSelectedImage(event.target.files[0]);
              onChange(event); // calling onChange returned from register 
            }}
          />
       ...
  );
}

3- Since your input type is file so, the value of your photo field has length property that you can use it to handle your validation like this:

const schema = yup.object().shape({
  photo: yup
    .mixed()
    .test("required", "photo is required", value => value.length > 0)
    .test("fileSize", "File Size is too large", (value) => {
      return value.length && value[0].size <= 5242880;
    })
    .test("fileType", "Unsupported File Format", (value) =>{
      return value.length && ["image/jpeg", "image/png", "image/jpg"].includes(value[0].type)
    }
    )
});

Here is the full edited version of your file.

Upvotes: 6

Related Questions