我想实现一个更高阶的React组件,该组件可用于轻松跟踪任何React组件上的事件(例如单击)。这样做的目的是轻松将点击(和其他事件)吸引到我们的第一方分析跟踪器中。
我遇到的挑战是,React综合事件系统要求事件(如onClick)必须绑定到以响应DOM元素(如)div。如果我要包装的组件是自定义组件,就像每个通过高阶函数实现的HOC一样,则我的click事件无法正确绑定。
onClick
div
例如,使用此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在每个孩子上使用a ,并在Ref填充后手动绑定我的click事件。
Ref
任何想法或其他解决方案表示赞赏!
更新: 使用remapChildren从@estus技术的答案,使包装的成分更手动的方式,我能得到这个工作作为一个高阶函数- https://codesandbox.io/s/3rl9rn1om1
remapChildren
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>; }; };
无法Wrapper通过常规方法(例如ref或)从React元素获取对基础DOM节点的引用(并且可以有多个)ReactDOM.findDOMNode。为此,应递归遍历子元素。
Wrapper
ReactDOM.findDOMNode
一个例子:
remapChildren(children) { const { onClick } = this; return React.Children.map( children, child => { if (typeof child.type === 'string') { return React.cloneElement(child, { onClick }); } else if (React.Children.count(child.props.children)) { return React.cloneElement(child, { children: this.remapChildren( child.props.children ) }); } } ); } render() { return this.remapChildren(this.props.children); }
remapChildren地方onClick只对DOM元素。请注意,此实现会跳过嵌套的DOM元素。