起因
因为部门前端系统越来越多,为了项目稳定运行、统计汇总、及时定位线上bug,急需前端埋点系统,并且对项目代码侵入性越小越好。所以急需一套react透明埋点方式。
组件写法 函数组件和类组件两种形式常用形式,还有就是createElement的写法,多用于写一些类库或者UI组件库使用。且前两种打包的时候也会转成后者。
侵入性最小且能在全局作用,只能从react入手了。劫持一波createElement。so,让我们先来撸一波源码。
ReactElement.createElement = function (type, config, children) {
  var propName;
  // 用于存储后面的属性
  var props = {};
  var key = null; // 元素的key
  var ref = null;  // 元素的ref
  var self = null; 
  var source = null;
  if (config != null) {
    // 判断是否有ref,有就赋值一下
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    // 同理
    if (hasValidKey(config)) {
      key = '' + config.key;
    }
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    // 把config里面的属性都一个一个挪到props中
    for (propName in config) {
      // 判断是不是原型链上的属性
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }
  // children 可能是一个也可能是多个
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    // 只有一个children
    props.children = children;
  } else if (childrenLength > 1) {
    // 遍历一下,把children放到 childArray上
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    if (process.env.NODE_ENV !== 'production') {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    // 把这个数组赋值给props.children
    props.children = childArray;
  }
  // 有type并且type有defaultProps属性 type是一个组件
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    // 同样的遍历
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (process.env.NODE_ENV !== 'production') {
    if (key || ref) {
      if (typeof props.typeof === 'undefined' || props.typeof !== REACT_ELEMENT_TYPE) {
        var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;
        if (key) {
          defineKeyPropWarningGetter(props, displayName);
        }
        if (ref) {
          defineRefPropWarningGetter(props, displayName);
        }
      }
    }
  }
  // props里面存的是config的属性值,然后还有children的属性
  // return一个 调用ReactElement执行方法,并传入刚才处理过的参数
  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};
比较简单的代码,所以我们可以从props上入手,如果props上有onCLick属性的,那么我们就在onClick触发前调用我们的埋点方法。目测可行。 具体的埋点方案,下次再说。
 
			
文章评论