skip to Main Content

I am a newbie to web-dev and learning React. I have used ZOD for form implementation. My IDE is not showing any errors but when I click on submit button, screen doesn’t gets re-render. It would be nice if someone can help me out. I know its a small issue, but I have been scratching my head for over a day.

APP.TSX
import { useEffect, useState } from "react";
import StudentGradingEvaluationForm, {
  StudentFormData,
} from "./Components/StudentGradingEvaluationForm";
import GPACalculator from "./Components/GPACalculator";
import "./Components/Courses";

const App = () => {
  const [formData, setFormData] = useState<StudentFormData | null>(null);
  const [isFormSubmitted, setIsFormSubmitted] = useState(false);

  const handleFormSubmitted = (data: StudentFormData) => {
    if (data) {
      setFormData(data);
      setIsFormSubmitted(true);
    }
  };

  const resetForm = () => {
    setFormData(null);
    setIsFormSubmitted(false);
  };

  return (
    <>
      <div style={{ textAlign: "center" }}>
        <h1>GPA Calculator for Individual Student</h1>
      </div>
      <div>
        {!isFormSubmitted && (
          <StudentGradingEvaluationForm onSubmit={handleFormSubmitted} />
        )}
        {isFormSubmitted && !formData && (
          <p className="text-danger">Enter correct credentials</p>
        )}
      </div>
      {formData && (
        <button className="btn btn-outline-danger" onClick={resetForm}>
          Reset Form
        </button>
      )}
      {formData && formData.courses && (
        <GPACalculator
          subject={formData.courses}
          number={formData.number}
          name={formData.name}
        />
      )}
    </>
  );
};

export default App;
StudentGradingEvaluationForm.tsx

import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import courses from "./Courses";

const schema = z.object({
  name: z
    .string()
    .min(3, { message: "Description should be atleast 3 characters." }),
  number: z.number().min(0).max(100),
  courses: z.enum(courses, {
    errorMap: () => ({ message: "Course is required." }),
  }),
});

export type StudentFormData = z.infer<typeof schema>;

interface Props {
  onSubmit: (data: StudentFormData) => void;
}

const StudentGradingEvaluationForm = ({ onSubmit }: Props) => {
  const { register, handleSubmit } = useForm<StudentFormData>({
    resolver: zodResolver(schema),
  });

  return (
    <form
      onSubmit={handleSubmit((data) => {
        onSubmit(data);
        console.log(onSubmit);
      })}
    >
      <div className="mb-3">
        <label htmlFor="studentName" className="form-label">
          Name of Student
        </label>
        <input
          id="studentName"
          type="text"
          className="form-control"
          {...register("name")}
        />
      </div>
      <div className="mb-3">
        <label htmlFor="courseName" className="form-label">
          Name of Course
        </label>
        <div>
          <select
            id="courseName"
            className="select-control"
            {...register("courses")}
          >
            <option value=""></option>
            {courses.map((course) => (
              <option key={course} value={course}>
                {course}
              </option>
            ))}
          </select>
        </div>
      </div>
      <div className="mb-3">
        <label htmlFor="number" className="form-label">
          Enter Number
        </label>
        <input
          id="number"
          type="number"
          className="form-control"
          {...register("number")}
        />
      </div>
      <button type="submit" className="btn btn-primary">
        Submit
      </button>
    </form>
  );
};

export default StudentGradingEvaluationForm;
Courses.ts

const courses = [
  "Mechanics of Materials - I",
  "Fluid Dynamics - I",
  "Ordinary Differential Equations",
  "Thermodynamics - II",
  "Basic Electrical and Electronics Engineering",
] as const;

export default courses;
GPACalculator.tsx

interface Props {
  subject: string;
  name: string;
  number: number;
}
const GPACalculator = ({ subject, number, name }: Props) => {
  const calculateGpa = () => {
    if (number < 100 && number >= 80) return "A";
    else if (number < 80 && number >= 65) return "B";
    else if (number < 65 && number >= 55) return "C";
    else if (number < 55 && number >= 40) return "D";
    else return "FAIL";
  };
  return (
    <div>
      <h2>GPA Calculator Result for {name}</h2>
      <p>Subject: {subject}</p>
      <p>Number: {number}</p>
      <p>GPA: {calculateGpa()}</p>
    </div>
  );
};

export default GPACalculator;

I have used following dependencies:

npm create [email protected] npm i bootstrap npm i zod npm i [email protected] npm i @hookform/[email protected]

VS Code isn’t showing any error. Soon as I click on submit button, nothing happens. I believe my code is simple and self-explanatory. Looking forward for help.

2

Answers


  1. So the issue is, there is no error on your code. Your code is working fine. But you have form validation error for zod resolver. And as you are not showing any form error, you can not see the problem here.

    Attaching the error you were getting with your current code –
    enter image description here

    How to fix:

    <input
          id="number"
          type="text"
          className="form-control"
          {...register("number", {
            valueAsNumber: true,
          })}
        />
    

    just register the number input like I have shown here.

    Another thing:

    const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(schema),});
    console.log("errors =====>", errors)
    

    update these lines in your code at the top of StudentGradingEvaluationForm component to see the error states log.

    Please upvote if this helps!

    Let me know if you have any questions.

    Login or Signup to reply.
  2. By default, react-hook-form treats input values as strings

    I updated Schema z.number() to z.coerce.number()

    const schema = z.object({
      name: z.string().min(3, { message: "Description should be atleast 3 characters." }),
      number: z.coerce
        .number()
        .min(1, { message: "number is less than 1" })
        .max(100, { message: "number is more than 100" }),
      courses: z.enum(courses, {
        errorMap: () => ({ message: "Course is required." }),
      }),
    });
    

    I add message for better understanding

      <form
          onSubmit={handleSubmit((data) => {
            onSubmit(data);
            console.log(onSubmit);
          })}>
          <div className='mb-3'>
            <label htmlFor='studentName' className='form-label'>
              Name of Student
            </label>
            <input id='studentName' type='text' className='form-control' {...register("name")} />
            <span className='text-danger d-block  mt-2'>{formState.errors?.name?.message}</span>
          </div>
          <div className='mb-3'>
            <label htmlFor='courseName' className='form-label'>
              Name of Course
            </label>
            <div>
              <select id='courseName' className='select-control' {...register("courses")}>
                <option value=''></option>
                {courses.map((course) => (
                  <option key={course} value={course}>
                    {course}
                  </option>
                ))}
              </select>
    
              <span className='text-danger d-block  mt-2'>{formState.errors?.courses?.message}</span>
            </div>
          </div>
          <div className='mb-3'>
            <label htmlFor='number' className='form-label'>
              Enter Number
            </label>
            <input id='number' type='number' className='form-control' {...register("number")} />
            <span className='text-danger d-block  mt-2'>{formState.errors?.number?.message}</span>
          </div>
          <button type='submit' className='btn btn-primary'>
            Submit
          </button>
        </form>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search