10

I am trying to use React hook form with NumberFormat without Controller and without ReactDOM.findDOMNode (which is deprecated and discouraged). The following code works

import React from 'react';
import ReactDOM from 'react-dom';
import { useForm } from 'react-hook-form';
import NumberFormat from 'react-number-format';

function FormWorking() {
  const { register, handleSubmit, getValues } = useForm();

  function onSubmit() {
    console.log(getValues());
  }

  const cardNumberReg = register('cardNumber');
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <NumberFormat
          format="#### #### #### ####"
          {...cardNumberReg}
          ref={(inst) => (cardNumberReg.ref(ReactDOM.findDOMNode(inst)))}
      />
    </form>
  );
}

ReactDOM.render(
  <FormWorking />, document.getElementById('root')
);

but I don't want to use findDOMNode. None of the below attempts is working (cardNumber is blank or undefined in the log)

      <NumberFormat
          format="#### #### #### ####"
          {...cardNumberReg}
          getInputRef={(e: any) => (cardNumberReg.ref(e))}
      />

      <NumberFormat
          format="#### #### #### ####"
          {...cardNumberReg}
          ref={cardNumberReg.ref}
      />

      <NumberFormat
          format="#### #### #### ####"
          {...cardNumberReg}
          ref={(e) => cardNumberReg.ref(e)}
      />

I am new to react and any help would be greatly appreciated.

1 Answer 1

16

My take on this is to use the Controller component from react hook form, in that case you are handling the NumberFormat as a controlled component, you need to do something like this:

import { useForm, Controller } from "react-hook-form";
import NumberFormat from "react-number-format";

export default function App() {
  const {
    control,
    handleSubmit,
    formState: { errors }
  } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        control={control}
        name="cardNumber"
        render={({ field: { onChange, name, value } }) => (
          <NumberFormat
            format="#### #### #### ####"
            name={name}
            value={value}
            onChange={onChange}
          />
        )}
      />
      <input type="submit" />
    </form>
  );
}

Basically you need to pass the control value coming from the useForm() function and give the Controller a name, in your case is cardNumber, after that you will use a render function in the Controller, where your NumberFormat controller will be used, notice that the render prop is a function that gives you all the necessary values in order to make your input work, like the onChange, the value and the name. You can take a look at the docs to see all the available props.

Keep in mind that normally you want to use the register function for every input, but there are cases with UI libraries that using the Controller to make the input controlled is the best idea

Also here's a sandbox with a working example.

Sign up to request clarification or add additional context in comments.

4 Comments

I was hoping for a solution using uncontrolled components which is a main selling point of react hook form but I think you are right that the solution you provided is the best way for these two libraries to integrate. I appreciate your time answering this question.
how do I pass ref to NumberFormat? I think it is still needed for reset function to work?
@AlexZvl you have two options, one is to pass in the reset the value like this reset({ "cardNumber": "" }), or explicitly call setValue like this: setValue("cardNumber", "")
Saved me a couple of hours! Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.