Skip to content

Instantly share code, notes, and snippets.

@s875515
Last active January 10, 2018 08:16
Show Gist options
  • Save s875515/3a5a2f911a2db00c75dc993335f4b4f3 to your computer and use it in GitHub Desktop.
Save s875515/3a5a2f911a2db00c75dc993335f4b4f3 to your computer and use it in GitHub Desktop.
react-ga event tracking function common component solution. If have any better solution that comment below. thanks
import * as React from 'react';
import * as gaModel from '~/model/gaModel';
import gaUtil from '~/util/gaUtil';
/**
* 為了省略不必要的div層去觸發ga event
* 會分成兩種做法
*
* 一、
* GaBox拿來包的是 自定義component 的話:
* 一樣還是會去在最外層包一層div,去觸發event(有更好的做法請聯絡
* 所以會有破版可能,若有影響請自行寫style調整
*
* 二、
* GaBox拿來包的是 一般jsx 的話:
* 就會直接利用react.flagment去省略掉div層
* 用cloneElement將onClick事件再包裝
* 若原本下層就有click事件的話,也會將其包裝進來
* 不會影響到原本onclick運作
*
*/
interface props {
// className
className?: string;
// style
style?: any;
// child element
children: any;
/**
* 頁面
* e.q. (依據路由)
* 小遊戲:game
*/
page: string;
/**
* 位置
* e.q. (底線區隔、小寫)
* 熱門遊戲列表: hot_list
*/
position: string;
/**
* 事件
* click | view | hover
* 預設會為click
* 依據需要的event丟陣列進來
*/
event?: [gaModel.gaEvent];
/**
* 標籤
* e.q. (底線區隔、小寫)
* 小遊戲:bbin_糖果派對
*/
label?: string;
}
class GaBox extends React.PureComponent<props> {
static defaultProps: props = {
page: '',
position: '',
event: [gaModel.gaEvent.click],
children: '',
};
componentDidMount(): void {
this.handleEvent(gaModel.gaEvent.view)();
}
handleEvent = (eventFlag: gaModel.gaEvent): any => (): void => {
const { page, position, event, label }: props = this.props;
if (event && event.indexOf(eventFlag) > -1) {
const action: string = `${page}.${position}.${eventFlag}`;
gaUtil.logEvent(action, label);
}
}
render(): JSX.Element {
// 包裝 自定義 component
if (!isJsx(this.props.children.type)) {
return (
<div
className={this.props.className}
style={this.props.style}
onClick={this.handleEvent(gaModel.gaEvent.click)}
onMouseOver={this.handleEvent(gaModel.gaEvent.hover)}
>
{this.props.children}
</div>
);
}
// 包裝 一般JSX element
const child: JSX.Element = React.cloneElement(this.props.children, {
onClick: (): void => {
const handleClickFunc: any = this.props.children.props.onClick;
this.handleEvent(gaModel.gaEvent.click)();
// 觸發原本click事件
handleClickFunc && handleClickFunc();
},
onMouseOver: (): void => {
const handleMouseOverFunc: any = this.props.children.props.onMouseOver;
this.handleEvent(gaModel.gaEvent.hover)();
// 觸發原本onMouseOver事件
handleMouseOverFunc && handleMouseOverFunc();
},
});
return (
<React.Fragment>
{child}
</React.Fragment>
);
}
}
const isJsx: any = (type: string): boolean => {
const all_html: any[] = [
'span',
'address',
'applet',
'area',
'article',
'aside',
'base',
'basefont',
'bgsound',
'blockquote',
'body',
'br',
'button',
'caption',
'center',
'col',
'colgroup',
'dd',
'details',
'dir',
'div',
'dl',
'dt',
'embed',
'fieldset',
'figcaption',
'figure',
'footer',
'form',
'frame',
'frameset',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'header',
'hgroup',
'hr',
'html',
'iframe',
'img',
'input',
'isindex',
'li',
'link',
'listing',
'main',
'marquee',
'menu',
'menuitem',
'meta',
'nav',
'noembed',
'noframes',
'noscript',
'object',
'ol',
'p',
'param',
'plaintext',
'pre',
'script',
'section',
'select',
'source',
'style',
'summary',
'table',
'tbody',
'td',
'template',
'textarea',
'tfoot',
'th',
'thead',
'title',
'tr',
'track',
'ul',
'wbr',
'xmp',
'applet',
'caption',
'html',
'table',
'td',
'th',
'marquee',
'object',
'template',
'foreignObject',
'desc',
'title',
'dd',
'dt',
'li',
'option',
'optgroup',
'p',
'rp',
'rt',
];
return all_html.indexOf(type) > -1;
};
export default GaBox;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment