react-datepicker icon indicating copy to clipboard operation
react-datepicker copied to clipboard

customInput remounts on every render

Open JavRok opened this issue 4 years ago • 7 comments

Hi, I think there's a performance issue when using customInput option with react-datepicker. The provided custom input gets created/mounted on every render of the parent.

The problem can be seen in this sandbox: Edit React Hook Form - Controller (forked) Here I was testing it together with react-hook-form, but I commented the integration to prove the problem is on the datepicker. I followed the example here -> https://reactdatepicker.com/#example-custom-input.

I added local state (open) to force parent rendering, and useEffect to log the element remounting.

This may not seem like a big problem, but this is a simple example. On my project I'm using a heavier custom element and the performance hit is pretty obvious.

I don't know if the solution is fixable here or I'm gonna have to use some kind of hook/memoization. Any clues?

Thanks and keep up the good work !

  • OS: Ubuntu on WLS
  • Browser Chrome
  • Version 86

JavRok avatar Oct 21 '20 16:10 JavRok

Oh, and seems forwardRef is also necessary, as commented by @Psvensso on this other issue https://github.com/Hacker0x01/react-datepicker/issues/2397#issuecomment-707048538

JavRok avatar Oct 21 '20 16:10 JavRok

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 02 '21 17:06 stale[bot]

Same here. This is even more visible when you pass onChange handler, and try to manually type the date. You will lose focus on each render.

In my case, adding useMemo hook solve the issue

const CustomInput = React.useMemo(
  () => forwardRef((props, ref) => <input {...props} ref={ref} />),
  [],
);

davidfrtala avatar Jun 10 '21 12:06 davidfrtala

Same here. This is even more visible when you pass onChange handler, and try to manually type the date. You will lose focus on each render.

In my case, adding useMemo hook solve the issue

const CustomInput = React.useMemo(
  () => forwardRef((props, ref) => <input {...props} ref={ref} />),
  [],
);

Could you post a full example of this? Thanks!

jlei523 avatar Jun 25 '21 10:06 jlei523

If anyone is looking for full example here it is with custom tailwind component

const DatePicker = ({
  value,
  onChange,
  label,
  showError,
  placeholder,
}: IDatePicker): JSX.Element => {
  const ref = createRef<HTMLInputElement>();

  const CustomInput = useMemo(
    () =>
      forwardRef<HTMLInputElement, unknown>(({ ...rest }) => (
        <div className={styles['outline-container']}>
          {label && <label>{label}</label>}
          <input
            ref={ref}
            {...rest}
            className={!value && showError ? 'input-error' : ''}
            type="text"
            autoComplete="bday"
          />
          <Icon
            className={`absolute text-gray-500 right-4 ${
              label ? '' : '-translate-y-1/2'
            } top-1/2 transform stroke-current`}
            name="calendar"
          />
        </div>
      )),
    []
  );

  return (
    <ReactDatePicker
      customInput={<CustomInput ref={ref} />}
      selected={value}
      locale={ru}
      dateFormat="dd.MM.yyyy"
      portalId="root"
      onChange={onChange}
      placeholderText={placeholder}
    />
  );
};

ShivamJoker avatar Jan 16 '22 09:01 ShivamJoker

If anyone is looking for full example here it is with custom tailwind component

const DatePicker = ({
  value,
  onChange,
  label,
  showError,
  placeholder,
}: IDatePicker): JSX.Element => {
  const ref = createRef<HTMLInputElement>();

  const CustomInput = useMemo(
    () =>
      forwardRef<HTMLInputElement, unknown>(({ ...rest }) => (
        <div className={styles['outline-container']}>
          {label && <label>{label}</label>}
          <input
            ref={ref}
            {...rest}
            className={!value && showError ? 'input-error' : ''}
            type="text"
            autoComplete="bday"
          />
          <Icon
            className={`absolute text-gray-500 right-4 ${
              label ? '' : '-translate-y-1/2'
            } top-1/2 transform stroke-current`}
            name="calendar"
          />
        </div>
      )),
    []
  );

  return (
    <ReactDatePicker
      customInput={<CustomInput ref={ref} />}
      selected={value}
      locale={ru}
      dateFormat="dd.MM.yyyy"
      portalId="root"
      onChange={onChange}
      placeholderText={placeholder}
    />
  );
};

Cheers! Did you also manage to make this component responsive on phones when including time?

RobSchilderr avatar Feb 04 '22 20:02 RobSchilderr

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Aug 13 '22 06:08 stale[bot]