omponente de reação de ordem superior para rastreamento de cliques
Gostaria de implementar um componente de reação de ordem superior, que pode ser usado para rastrear eventos facilmente (como um clique) em qualquer componente do React. O objetivo disso é conectar facilmente cliques (e outros eventos) ao nosso rastreador de análise de primeira parte.
O desafio que me deparei é que o sistema de eventos sintéticos React requer eventos (comoonClick
) deve reagir a elementos DOM, como umdiv
. Se o componente que estou agrupando for um componente personalizado, como todo HOC implementado por meio de uma função de ordem superior, meus eventos de clique não serão vinculados corretament
Por exemplo, usando este HOC, oonClick
manipulador será acionado para o button1, mas não para o button
// Higher Order Component
class Track extends React.Component {
onClick = (e) => {
myTracker.track(props.eventName);
}
render() {
return React.Children.map(
this.props.children,
c => React.cloneElement(c, {
onClick: this.onClick,
}),
);
}
}
function Wrapper(props) {
return props.children;
}
<Track eventName={'button 1 click'}>
<button>Button 1</button>
</Track>
<Track eventName={'button 2 click'}>
<Wrapper>
<button>Button 2</button>
</Wrapper>
</Track>
CodeSandbox com exemplo de trabalho: https: //codesandbox.io/embed/pp8r8oj71
Meu objetivo é poder usar um HOF como este (opcionalmente como decorador) para rastrear cliques em qualquer definição de componente do Reac
export const withTracking = eventName => Component => props => {
return (
<Track eventName={eventName}>
{/* Component cannot have an onClick event attached to it */}
<Component {...props} />
</Track>
);
};
A única solução que consigo pensar no atm é usar umRef
em cada filho e vincular manualmente meu evento de clique uma vez que oRef
é preenchido.
Todas as idéias ou outras soluções são bem-vindas!
ATUALIZAR Usando oremapChildren
técnica da resposta do @estus e uma maneira mais manual de renderizar os componentes embrulhados, consegui fazer com que isso funcionasse como uma função de ordem superior -https: //codesandbox.io/s/3rl9rn1om
export const withTracking = eventName => Component => {
if (typeof Component.prototype.render !== "function") {
return props => <Track eventName={eventName}>{Component(props)}</Track>;
}
return class extends Component {
render = () => <Track eventName={eventName}>{super.render()}</Track>;
};
};