javascript - 用于点击跟踪的高阶 React 组件

标签 javascript reactjs dom-events high-order-component

我想实现一个更高阶的 React 组件,该组件可用于轻松跟踪任何 React 组件上的事件(如点击)。这样做的目的是轻松地将点击(和其他事件)连接到我们的第一方分析跟踪器中。

我遇到的挑战是 React 合成事件系统需要事件(如 onClick)绑定(bind)以响应 DOM 元素,如 div。如果我包装的组件是自定义组件,就像通过高阶函数实现的每个 HOC 一样,我的点击事件不会正确绑定(bind)。

例如,使用此 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>
  );
};

我能想到的唯一解决方案是在每个 child 上使用 Ref 并在填充 Ref 后手动绑定(bind)我的点击事件。

如有任何想法或其他解决方案,我们将不胜感激!

更新: 使用@estus 的回答中的remapChildren 技术和一种更手动的渲染包装组件的方法,我能够让它作为高阶函数工作 - 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>;
  };
};

最佳答案

不可能通过常规方式从 Wrapper React 元素获取对底层 DOM 节点的引用(并且可以有多个节点),例如 ref 或 ReactDOM.findDOMNode。为此,应递归遍历子元素。

example :

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 仅在 DOM 元素上放置 onClick。请注意,此实现会跳过嵌套的 DOM 元素。

关于javascript - 用于点击跟踪的高阶 React 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52705522/

相关文章:

javascript - 如何检查事件是否被触发或何时使用按键与按键?

javascript - 通过一组坐标,两个坐标之间的最短路径 - Javascript

javascript - 如何使用 javascript 创建具有 id 名称的元素?

javascript - 如何在 react 中设置按钮在特定条件下禁用?

reactjs - 没有找到匹配的文件...。 (ReactJS)

javascript - Opera 中 document.onload 事件中插件的事件监听器

javascript - 在数据表中垂直滚动动画

javascript - Meteor 将输入存储在集合中

javascript - 在 Javascript 中迭代分页 API 结果

javascript - 更新控件模糊的 ValidationSummary 列表?