Search code examples
javascriptreactjsreact-hook-formreactstrap

Form validation not working with React hooks form version 7 with Reactstrap


Form validation not working with React strap and React hook form version 7. In the above sandbox project, when I click the submit button without entering the text to the bio input getting an error bio field is required. then when I type on that field, the error message, not disappear. Version 7 working very well with normal HTML forms and elements. but getting some conflict with reactstrap.

React version : 17.2 React hook form version : 7.22 Reactstrap version : 9.0

import "./styles.css";
import { Form, FormGroup, Input, Label, Button } from "reactstrap";
import * as Yup from "yup";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

export default function App() {
  const schema = Yup.object().shape({
    bio: Yup.string().required()
  });

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors }
  } = useForm({
    resolver: yupResolver(schema)
  });

  const submitHandle = (data) => {
    console.log(data);
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Form onSubmit={handleSubmit(submitHandle)} onReset={reset}>
        <FormGroup>
          <Label for="bio">Bio</Label>
          <Input id="bio" name="bio" type="text" {...register("bio")} />
          {errors.bio && <p className="invalid">{errors.bio.message}</p>}
        </FormGroup>
        <FormGroup>
          <br/>
          <Button color="primary">Save</Button>
        </FormGroup>
      </Form>
    </div>
  );
}

Code sandbox : https://codesandbox.io/s/ancient-smoke-0ccbn


Solution

  • I didn't find anything in your sandbox link, but your problem is because of the ref, react-hook-form need to access ref of input, while reactstrap's Input component exposes ref by innerRef prop, so there are two solutions to solve your problem:

    1- manually register field like this:

    default function App() {
      ...
      const {ref,...bio} = register('bio');
      return (
       <Form onSubmit={handleSubmit(submitHandle)} onReset={reset}>
          <FormGroup>
            <Label for="bio">Bio</Label>
            <Input id="bio" name="bio" type="text"  {...bio} innerRef={ref}/>
            {errors.bio && <p className="invalid">{errors.bio.message}</p>}
          </FormGroup>
        </Form>
      );
    }
    

    2- Use the Controller component, which will take care of the registration process, like this:

    default function App() {
      ...
     const {
      handleSubmit,
      reset,
      control,
      formState: { errors },
     } = useForm({
      resolver: yupResolver(schema),
      defaultValues: { bio: '' },
     });
      ...
      return (
       <Form onSubmit={handleSubmit(submitHandle)} onReset={reset}>
          <FormGroup>
            <Label for="bio">Bio</Label>
            <Controller
              id="bio"
              name="bio" 
              control={control}
              render={({ field }) => <Input {...field} />}
            />
            {errors.bio && <p className="invalid">{errors.bio.message}</p>}
          </FormGroup>
        </Form>
      );
    }