не очень хорошая вещь, лучше сделать метод-прототип по соображениям совместимости,
ел бы реализовать компонент реагирования более высокого порядка, который можно использовать для простого отслеживания событий (например, щелчка) в любом компоненте React. Цель этого - легко подключить клики (и другие события) к нашему первому стороннему аналитическому трекеру.
Проблема, с которой я столкнулся, заключается в том, что синтетическая система событий React требует событий (например,onClick
) быть обязанным реагировать на элементы DOM, какdiv
, Если компонент, который я обертываю, является пользовательским компонентом, как и любой HOC, реализованный с помощью функции более высокого порядка, мои события щелчка не связываются правильно.
Например, используя этот HOC,onClick
обработчик будет срабатывать для button1, но не для button2.
// 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 с рабочим примером: https://codesandbox.io/embed/pp8r8oj717
Моя цель состоит в том, чтобы иметь возможность использовать такой HOF (необязательно в качестве декоратора) для отслеживания кликов по любому определению компонента React.
export const withTracking = eventName => Component => props => {
return (
<Track eventName={eventName}>
{/* Component cannot have an onClick event attached to it */}
<Component {...props} />
</Track>
);
};
Единственное решение, которое я могу придумать, это использоватьRef
на каждого ребенка и вручную связывая мое событие клика как толькоRef
населён.
Любые идеи или другие решения приветствуются!
ОБНОВИТЬ: С помощьюremapChildren
Техника ответа @estus и более ручной способ рендеринга обернутых компонентов, я смог заставить это работать как функция более высокого порядка -https://codesandbox.io/s/3rl9rn1om1
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>;
};
};