Home > OS >  Extend React forwardRef component with methods
Extend React forwardRef component with methods

Time:12-01

I want to create an extended component with some additional functions added.

Let's say I have an ExtendedButton component which has a button that is forwardRef:ed, but which also has a doubleClick method. I know this is a silly example, but something like this:

const ExtendedButton = forwardRef<HTMLButtonElement, React.HTMLAttributes<HTMLButtonElement>>((props, ref) => {
  const btnRef = useRef<HTMLButtonElement>(null);
  useImperativeHandle(ref, () => btnRef?.current as HTMLButtonElement);

  const doubleClick = () => {
    btnRef.current?.click();
    btnRef.current?.click();
  };

  return <button {...props} ref={btnRef}></button>;
});

I want to be able to get the doubleClick method, as well as all the methods on the button, from a consumer component like this:

export const Consumer = () => {
  const ref = useRef<HTMLButtonElement>(null);

  ref.current.doubleClick();
  ref.current.click();

  return <ExtendedButton ref={ref}></ExtendedButton>;
};

I feel I should probably remove the forwardRef so the ref is pointing to ExtendedButton instead of button, but how can I get the button methods then?

Thanks!

CodePudding user response:

useImperativeHandle should expose all the methods you want to access:

type ExtendedButtonType = HTMLButtonElement & { doubleClick: () => void }
const ExtendedButton = forwardRef<ExtendedButtonType, React.HTMLAttributes<HTMLButtonElement>>(
  (props, ref) => {
    const btnRef = useRef<HTMLButtonElement>(null)
    const doubleClick = (): void => {
      btnRef.current?.click()
      btnRef.current?.click()
    }
    useImperativeHandle(
      ref,
      () =>
        ({
          ...btnRef.current,
          doubleClick,
        } as ExtendedButtonType),
    )

    return <button {...props} ref={btnRef} />
  },
)

export const Consumer: FC = () => {
  const ref = useRef<ExtendedButtonType>(null)

  ref.current?.doubleClick()
  ref.current?.click()

  return <ExtendedButton ref={ref} />
}

CodePudding user response:

add the method inside the useImperativeHandle

  const ExtendedButton = forwardRef<HTMLButtonElement, React.HTMLAttributes<HTMLButtonElement>>((props, ref) => {
      const btnRef = useRef<HTMLButtonElement>( );
     
      
      useImperativeHandle(ref, () => ({

        ...btnRef.current,
        doubleClick: () => {
          btnRef.current?.click();
          btnRef.current?.click();
         };
      }));
    
      return <button {...props} ref={btnRef}></button>;
    });
  • Related