I'm trying to write a Polymorphic component in React that supports both host elements such as (div, button, etc) and custom React components.
but there's a constraint of needing whatever component is passed in to the as prop that it must have an onClick prop
here's my work in progress.
import React, { useCallback, useRef, useLayoutEffect } from 'react';
export type GaClickTrackerProps<Type extends React.ElementType> = {
as: Type;
fieldsObject: {
hitType: UniversalAnalytics.HitType; // 'event'
eventCategory: string;
eventAction: string;
eventLabel?: string | undefined;
eventValue?: number | undefined;
nonInteraction?: boolean | undefined;
};
onClick?: (...args: any[]) => any;
} & React.ComponentPropsWithoutRef<Type>;
export function GaClickTracker<Type extends React.ElementType>({
onClick,
fieldsObject,
as: Component,
...props
}: GaClickTrackerProps<Type>) {
const fieldsObjectRef = useRef(fieldsObject);
const onClickRef = useRef(onClick);
useLayoutEffect(() => {
onClickRef.current = onClick;
fieldsObjectRef.current = fieldsObject;
});
const handleClick: React.MouseEventHandler<Type> = useCallback((event) => {
onClickRef.current?.(event);
if (fieldsObjectRef.current) {
ga('send', fieldsObjectRef.current);
}
}, []);
return (
<Component onClick={handleClick} {...props} />
);
}
React.createElementdirectly instead of using JSX. If you still really want to do this, you can useJSX.InstrinsicElements[TagName]and get the properties expected from the underlying HTML element you want to wrap, and then useOmit<..., "onClick">to omit the originalonClickthat's optional and set yours (which is also not recommended).