2

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!

2 Answers 2

1

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} />
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is there a way to do without as ExtendedButtonType?
Seems like removing as ExtendedButtonType is fine
0

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>;
    });

1 Comment

It works but throw error as follow: Types of property 'disabled' are incompatible. Type 'boolean | undefined' is not assignable to type 'boolean'

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.