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