ui icon indicating copy to clipboard operation
ui copied to clipboard

useCheckbox for React-Hook-Form + checkbox

Open ozzyfromspace opened this issue 2 years ago • 3 comments

React-Hook-Form was designed to work outside the react rendering lifecycle to create more performant forms, but the implementation of RHF HOC's is largely undoing this advantage. With this in mind, writing components that use RHF's register function is most ideal, and I think behind the scenes, using hooks to manage logic performantly is a better way.

Another benefit I see to using hooks instead of HOC's is portability of logic, as we're not necessarily going down the road of building complex logic into shadcn components, but rather making it opt-in through hooks. We also reduce the component abstraction, which is good.

For the first hook, I would like to propose an internal useCheckbox hook. The hook should avoid re-renders whenever the checkbox is clicked, but still update RHF's state appropriately. The client should never need to interact with this hook.

Example usage:

// page.tsx

const FormExample = () => {
  const { register, handleSubmit } = useForm()

  console.log("app rendering") // only once

  return (
    <form onSubmit={handleSubmit((data) => console.log("submitting...", data))}>
      <h3>Are you in?</h3>

      <div>
        <Checkbox {...register("terms")} value="of-course" id="terms" />
        <Label htmlFor="terms">Accept Terms & Conditions</Label>
      </div>

      <Button>Get started</Button>
    </form>
  )
}

// checkbox.tsx

const Checkbox = React.forwardRef<
  HTMLInputElement | null,
  React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, onChange, onBlur, ...props }, ref) => {
  **const { handleClick, spyRef } = useCheckbox({ ref, onChange, onBlur })**

  return (
    <CheckboxPrimitive.Root
      ref={spyRef}
      {...props}
      onClick={handleClick}
    >
      <CheckboxPrimitive.Indicator
      >
        <Check className="h-4 w-4" />
      </CheckboxPrimitive.Indicator>
    </CheckboxPrimitive.Root>
  )
})

I've never contributed to open-source before, so I'd like to apologize in advance if I'm not going about this the right way. Correct me, I'm willing to learn. What are your thoughts, community? Should we take a hooks-first approach to this RHF-shadcn integration? I'm willing to write a proper implementation (I already have something that's good enough for my needs).

Thanks, Ozzy.

ozzyfromspace avatar May 23 '23 07:05 ozzyfromspace

@ozzyfromspace This looks interesting. Thanks for the suggestion. I'll look into it and see how we can add this to the components. Might make a good forms guide as well.

shadcn avatar May 23 '23 16:05 shadcn

@shadcn Awesome, glad you're interested in seeing how this could go! I'll start working on a PR to make the discussion more concrete. I'd love to see a version of the form docs where we can register radix components without HOCs. That's the dream :)

ozzyfromspace avatar May 23 '23 20:05 ozzyfromspace

@shadcn I've created a PR for this 🎊

ozzyfromspace avatar May 29 '23 03:05 ozzyfromspace

I've closed this PR. I'm just gonna use the hook for my own projects. Best wishes to everyone working on this project. It's good work and I really hoped to add to it.

ozzyfromspace avatar Jun 05 '23 18:06 ozzyfromspace