Javascript 如何为上下文更改添加观察者?

Javascript 如何为上下文更改添加观察者?,javascript,reactjs,Javascript,Reactjs,我正在为我的react应用程序添加一个分析跟踪程序。我想主要捕捉两件事: 1) 所有点击事件。 2) 所有页面更改事件。 我试图找出解决此问题的方法,并在这方面找到了一些帮助: 上面的文章基本上让我创建了一个父包装器,并使用React上下文API将数据传递给嵌套元素。这个想法很好,但在阅读了上下文API之后,我仍然遗漏了一些内容 这是我按照这个模式得到的 Tracker.js import PropTypes from "prop-types" import * as React from "

我正在为我的react应用程序添加一个分析跟踪程序。我想主要捕捉两件事:
1) 所有点击事件。
2) 所有页面更改事件。

我试图找出解决此问题的方法,并在这方面找到了一些帮助:

上面的文章基本上让我创建了一个父包装器,并使用React上下文API将数据传递给嵌套元素。这个想法很好,但在阅读了上下文API之后,我仍然遗漏了一些内容

这是我按照这个模式得到的

Tracker.js

import PropTypes from "prop-types"
import * as React from "react"
import { connect } from "react-redux"

import TrackingManager from './TrackingManager'
import ScriptManager from "./ScriptManager"
import { isLeftClickEvent } from "../utils/Utils"

const trackingManager = new TrackingManager()
export const TrackerProvider = React.createContext()

/**
 * Tracking container which wraps the supplied Application component.
 * @param Application
 * @param beforeAction
 * @param overrides
 * @returns {object}
 */
class Tracker extends React.Component {
    constructor(props) {
      super(props)

      this.state = {
        pageName: ''
      }
    }

    componentDidMount() {
      this._addClickListener()
      this._addSubmitListener()
    }

    componentWillUnmount() {
      // prevent side effects by removing listeners upon unmount
      this._removeClickListener()
      this._removeSubmitListener()
    }

    componentDidUpdate() {
      console.log('TRACKER UPDATE')
    }

    pageLoad = pageName => {
        console.log('LOADING PAGE')
        this.setState({ pagename }, trackingManager.page(this.state))
    }
    /**
     * Add global event listener for click events.
     */
    _addClickListener = () => document.body.addEventListener("click", this._handleClick)
    /**
     * Remove global event listern for click events. 
     */
    _removeClickListener = () => document.body.removeEventListener("click", this._handleClick)
    /**
     * Add global event listener for submit events. 
     */
    _addSubmitListener = () => document.body.addEventListener("submit", this._handleSubmit)
    /**
     * Remove global event listern for click events. 
     */
    _removeSubmitListener = () => document.body.removeEventListener("submit", this._handleSubmit)

    _handleSubmit = event => {
        console.log(event.target.name)
    }

    _handleClick = event => {
      // ensure the mouse click is an event we're interested in processing,
      // we have discussed limiting to external links which go outside the
      // react application and forcing implementers to use redux actions for
      // interal links, however the app is not implemented like that in
      // places, eg: Used Search List. so we're not enforcing that restriction
      if (!isLeftClickEvent(event)) {
        return
      }

      // Track only events when triggered from a element that has 
      // the `analytics` data attribute.
      if (event.target.dataset.analytics !== undefined) {
        let analyticsTag = event.target.dataset.analytics
        console.log("Analytics:", analyticsTag)
        trackingManager.event("eventAction", {"eventName": analyticsTag, "pageName": "Something"})
      }
    }

    /**
     * Return  tracking script. 
     */
    _renderTrackingScript() {

        /**
         * If utag is already loaded on the page we don't  want to load it again
         */
        if (window.utag !== undefined) return

        /**
         * Load utag script. 
         */
        return (
          <ScriptManager
            account={process.env.ANALYTICS_TAG_ACCOUNT}
            profile={process.env.ANALYTICS_TAG_PROFILE}
            environment={process.env.ANALYTICS_TAG_ENV}
          />
        )
    }

    render() {
      return (
        <TrackerProvider.Provider value={
          {
            state: this.state, 
            loadPage: this.pageLoad
          }
        }>
          {this.props.children}
          {this._renderTrackingScript()}
        </TrackerProvider.Provider>
      )
    }
  }

export default Tracker
从“道具类型”导入道具类型
从“React”导入*作为React
从“react redux”导入{connect}
从“./TrackingManager”导入TrackingManager
从“/ScriptManager”导入ScriptManager
从“./utils/utils”导入{isLeftClickEvent}
const trackingManager=new trackingManager()
export const TrackerProvider=React.createContext()
/**
*包装提供的应用程序组件的跟踪容器。
*@param应用程序
*@param-beforeAction
*@param覆盖
*@返回{object}
*/
类跟踪器扩展了React.Component{
建造师(道具){
超级(道具)
此.state={
页面名:“”
}
}
componentDidMount(){
这是。_addClickListener()
这是.\u addSubmitListener()
}
组件将卸载(){
//通过在卸载时删除侦听器来防止副作用
此。_removeClickListener()
此._removeSubmitListener()
}
componentDidUpdate(){
console.log('TRACKER UPDATE')
}
pageLoad=pageName=>{
console.log('加载页面')
this.setState({pagename},trackingManager.page(this.state))
}
/**
*为单击事件添加全局事件侦听器。
*/
_addClickListener=()=>document.body.addEventListener(“单击”,此.\u handleClick)
/**
*删除单击事件的全局事件列表。
*/
_removeClickListener=()=>document.body.removeEventListener(“单击”,此.\u handleClick)
/**
*为提交事件添加全局事件侦听器。
*/
_addSubmitListener=()=>document.body.addEventListener(“提交”,this.\u handleSubmit)
/**
*删除单击事件的全局事件列表。
*/
_removeSubmitListener=()=>document.body.removeEventListener(“提交”,this.\u handleSubmit)
_handleSubmit=事件=>{
console.log(event.target.name)
}
_handleClick=事件=>{
//确保鼠标点击是我们感兴趣处理的事件,
//我们已经讨论了限制外部链接的问题
//react应用程序并强制实现者使用redux操作
//内部链接,但该应用程序并不像在中那样实现
//位置,例如:已使用的搜索列表。所以我们不强制执行该限制
如果(!isLeftClickEvent(事件)){
回来
}
//仅当从具有以下属性的元素触发时跟踪事件:
//“分析”数据属性。
if(event.target.dataset.analytics!==未定义){
让analyticsTag=event.target.dataset.analytics
日志(“分析:”,analyticsTag)
trackingManager.event(“eventAction”,{“eventName”:analyticsTag,“pageName”:“某物”})
}
}
/**
*返回跟踪脚本。
*/
_renderTrackingScript(){
/**
*如果页面上已经加载了utag,我们不想再次加载它
*/
如果(window.utag!==未定义)返回
/**
*加载utag脚本。
*/
返回(
)
}
render(){
返回(
{this.props.children}
{this.\u renderTrackingScript()}
)
}
}
导出默认跟踪器
index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Switch, Route } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './lib/store'
import history from './lib/history'



import MyComp from './containers/components/MyComp'
import Tracker from './lib/tracking/Tracker'

import './assets/stylesheets/bootstrap.scss'
import './bootstrap-ds.css'
import './index.css'
import './assets/stylesheets/scenes.scss'

ReactDOM.render((
<Tracker>
    <Provider store={store}>
        <Router history={history}>
            <Switch>
                <Route path={'/analytics'} component={MyComp}  />
            </Switch>
        </Router>
    </Provider>
</Tracker>
), document.getElementById('root'))
从“React”导入React
从“react dom”导入react dom
从“react Router dom”导入{Router,Switch,Route}
从“react redux”导入{Provider}
从“./lib/store”导入存储
从“/lib/history”导入历史记录
从“./containers/components/MyComp”导入MyComp
从“./lib/tracking/Tracker”导入跟踪器
导入“./assets/stylesheets/bootstrap.scss”
导入“./bootstrap ds.css”
导入“./index.css”
导入“./assets/stylesheets/sces.scss”
ReactDOM.render((
),document.getElementById('root'))
mycop.js

import React from 'react
import { TrackerProvider } from '../../lib/tracking/Tracker

const MyComp = () => {
    return (
        <TrackerProvider.Consumer>
         {context =>
              <>
                <div>This is my test page for track events for analytics</div>
                <button data-analytics="TEST_BUTTON">Test Analytics</button>
              </>
         }
        </TrackerProvider.Consumer>
    )
}

export default MyComp
从“React”导入React
从“../../lib/tracking/Tracker”导入{TrackerProvider}
常量mycop=()=>{
返回(
{context=>
这是我的分析跟踪事件测试页面
测试分析
}
)
}
导出默认mycop
以下是我正在努力解决的问题:
1.加载使用上下文的嵌套子组件时,如何通知父组件(
)触发某些函数?类似于
componentdiddupdate


本质上,用户导航到
MyComp
页面,并在
跟踪器中启动
pageLoad
功能。如何从
mycop
更新上下文,而不依赖render方法中的某个单击事件来运行函数。因此,也许在
componentdiddupdate
中,我可以更新上下文。

我注意到您在
react redux
中使用了
connect
。Redux已经向应用程序中的所有组件提供了它的状态,因此,如果您已经在使用Redux,就不需要直接处理上下文API

可以创建高阶组件(获取组件并返回组件的组件)并将事件侦听器附加到能够捕获应用程序中所有单击事件的组件

单击Dispatch HOC可能如下所示:

import React from 'react';
import { useDispatch } from 'react-redux';

import logClick from '../path/to/log/clicks.js';

const ClickLogger = Component => (...props) => {
  const dispatch = useDispatch();
  return <div onClick={e => dispatch(logClick(e))}>
    <Component {...props } />
  </div>;
};
从“React”导入React;
从'react redux'导入{useDispatch};
导入日志从“../path/to/log/cl”单击