Katharina Schreiber
Katharina Schreiber

Reputation: 1371

React Hook Form won't show error messages

I have a pretty tricky birthdate validation.

sandbox

As soon as the user tries to put a birthdate younger than 18 years old, the form updates to the date of today minus 18 years. Now, as I've been looking into it more closely, somehow I wish to integrate a notice, so that the user basically is aware, that his/hers birthdate was not accepted. For this I was trying to show a span handling an error message in my Form Component:

{errors.birthdate && (
   <span className="text-xs text-red-700">
      {errors.birthdate.message}
   </span>
)}

I also have a function for validation there:

const validate = (date) =>
  isOlderThen18Years(date) || "You must be at least 18 years old";

What is happening, as for resetting a date I am using useEffect in SelectBirthDay:

useEffect(() => {
    if (!isOlderThen18Years(value)) {
      onChange(
        set(new Date(), { year: getYear(value) }),
      );
    }  
  }, [value, onChange]);

So this resets the date, but how do I show the error message? So both is happening simultaneously? Surele I could work with some kind of alert. But is it possible to actually show the span in Form Component depending on useEffect outcome in selectBirthDay component?

Upvotes: 0

Views: 3116

Answers (1)

knoefel
knoefel

Reputation: 6949

You were very close by passing the error message to your onChange handler in <SelectBirthDay />.

I think a good option would be to separate your date selection as a component and then just handle the info message there. This way it's separated from the <Form /> component which doesn't have to know about this info message for the user as it is not really a validation message for the form field.

I also would suggest to move the generation of the years to the <SelectBirthYear /> component.

<SelectBirthDate />

import { useState } from "react";
import { SelectBirthDay } from "./SelectBirthDay";
import { SelectBirthMonth } from "./SelectBirthMonth";
import { SelectBirthYear } from "./SelectBirthYear";

export const SelectBirthDate = ({ onChange, ...field }) => {
  const [invalidMessage, setInvalidMessage] = useState();

  const handleChange = (value, invalidMessage) => {
    onChange(value);
    setInvalidMessage(invalidMessage);
  };
  return (
    <>
      <div className="sm:col-span-2 grid grid-cols-3 gap-4 mb-2">
        <div className="mt-1">
          <SelectBirthYear onChange={handleChange} {...field} />
        </div>
        <div className="mt-1">
          <SelectBirthMonth onChange={handleChange} {...field} />
        </div>
        <div className="mt-1">
          <SelectBirthDay onChange={handleChange} {...field} />
        </div>
      </div>
      <span className="mt-2 text-sm text-gray-500">{invalidMessage}</span>
    </>
  );
};

<SelectBirthDay />

export const SelectBirthDay = ({ value, onChange }) => {
  const handleChange = (date) => onChange(set(value, { date: date.getDate() }));

  const days = eachDayOfInterval({
    start: startOfMonth(value),
    end: endOfMonth(value)
  });

  useEffect(() => {
    if (!isOlderThen18Years(value)) {
      onChange(
        set(new Date(), { year: getYear(value) }),
        "Selected Date was not older then 18 years - automatically reset to the earliest possible date"
      );
    }
  }, [value, onChange]);
  
  return ...

<Form />

<Controller
  control={control}
  name="birthdate"
  rules={{ validate }}
  render={({ field: { ref, ...field } }) => (
    <SelectBirthDate {...field} />
  )}
/>
{errors.birthdate && (
  <span className="text-xs text-red-700">
    {errors.birthdate.message}
  </span>
)}

Edit validation-react-hook-form (forked)

Upvotes: 2

Related Questions