Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I avoid repeating a parameter in this React Hook Form form with shadcn/ui?

I’m trying to create a reusable input field, but I don’t know how to avoid repeating "control={form.control}". My problem is that "form" is defined in the "PracticeForm" component (as I need to declare it for the general form), not in "ItemInput", so I get an error:

PracticeForm.tsx:

import { useForm } from "react-hook-form";
import { Button } from "./ui/button";
import { Form } from "./ui/form";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import ItemInput from "./ItemInput";

const formSchema = z.object({
      username: z.string(),
      email: z.string()
      .email({
        message: "Please enter a valid email"
      })
    });
    
    const PracticeForm = () => {
      const form = useForm<z.infer<typeof formSchema>>({
        resolver: zodResolver(formSchema),
        defaultValues: {
          username: "",
          email: "email"
        },
      });
    
      function onSubmit(values: z.infer<typeof formSchema>) {
        console.log(values);
      }
    
      return (
        <div>
          <Form {...form}>
            <form
              onSubmit={form.handleSubmit(onSubmit)}
              className="flex flex-col w-52 gap-2"
            >
              <ItemInput name="username" placeholder={"Enter username"}/>
              <ItemInput name="email" placeholder={"Enter email"}/>
              <Button variant={"outline"} type="submit">
                Submit
              </Button>
            </form>
          </Form>
        </div>
      );
    };
    
    export default PracticeForm;

ItemInput.tsx:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import { FormControl, FormField, FormItem, FormMessage } from "./ui/form"
import { Input } from "./ui/input"

    type InputProps = {
        name: string
        placeholder: string
    }
    
    const ItemInput = ({name, placeholder}: InputProps) => {
      return (
        <div>
             <FormField
                control={form.control}
                name={name}
                render={({ field }) => (
                  <FormItem>
                    <FormControl>
                      <Input placeholder={placeholder} {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
        </div>
      )
    }
    
    export default ItemInput

Is there any way I can avoid repeating the "control={form.control" line every time I reuse the "ItemInput" custom component?

>Solution :

To avoid repetition, pass the control prop from the parent component to ItemInput. Here’s how:

Modify your ItemInput.tsx file as follows:

import { FormControl, FormField, FormItem, FormMessage } from "./ui/form";
import { Input } from "./ui/input";
import { Control } from "react-hook-form"; // Import Control type

type InputProps = {
  name: string;
  placeholder: string;
  control: Control; // Add control prop of type Control
};

const ItemInput = ({ name, placeholder, control }: InputProps) => {
  return (
    <div>
      <FormField
        control={control} // Use the control prop passed from the parent
        name={name}
        render={({ field }) => (
          <FormItem>
            <FormControl>
              <Input placeholder={placeholder} {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />
    </div>
  );
};

export default ItemInput;

Now, in your PracticeForm.tsx, you can pass the form control to the ItemInput component as a prop named control:

<ItemInput name="username" placeholder="Enter username" control={form.control} />
<ItemInput name="email" placeholder="Enter email" control={form.control} />

To avoid repeating the control={form.control} line and ensure ItemInput component has access to control object provided by react-hook-form, do this.

A helpful tip to prevent repetition is to use this technique.

// ItemInput.tsx

import { useFormContext } from "react-hook-form"; // Import useFormContext

type InputProps = {
  name: string;
  placeholder: string;
};

const ItemInput = ({ name, placeholder }: InputProps) => {
  const { control } = useFormContext(); // Use useFormContext to access the form control

  return (
    <div>
      <FormField
        control={control}
        name={name}
        render={({ field }) => (
          <FormItem>
            <FormControl>
              <Input placeholder={placeholder} {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />
    </div>
  );
};

export default ItemInput;
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading