title: How to add a watcher for context change?
body: <p>I am working on adding an analytics tracker to my react app. I want to primarily capture 2 things:<br />
  1) All click events.<br />
  2) All page change events.<br /> </p>
  
  <p>I was trying to figure out how to approach this problem and found some help on SO with this:
  <a href="https://stackoverflow.com/questions/57204995/how-can-i-create-a-wrapper-component-for-entire-app/57205047">How can I create a wrapper component for entire app?</a></p>
  
  <p>The above post basically had me creating a parent wrapper and using the React Context API to pass data to the nested elements. The idea is great, but I'm still missing a few pieces here after reading the context API.</p>
  
  <p>Heres what I have following that pattern.</p>
  
  <p>Tracker.js</p>
  
  <pre><code>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 =&gt; {
          console.log('LOADING PAGE')
          this.setState({ pagename }, trackingManager.page(this.state))
      }
      /**
       * Add global event listener for click events.
       */
      _addClickListener = () =&gt; document.body.addEventListener("click", this._handleClick)
      /**
       * Remove global event listern for click events. 
       */
      _removeClickListener = () =&gt; document.body.removeEventListener("click", this._handleClick)
      /**
       * Add global event listener for submit events. 
       */
      _addSubmitListener = () =&gt; document.body.addEventListener("submit", this._handleSubmit)
      /**
       * Remove global event listern for click events. 
       */
      _removeSubmitListener = () =&gt; document.body.removeEventListener("submit", this._handleSubmit)
  
      _handleSubmit = event =&gt; {
          console.log(event.target.name)
      }
  
      _handleClick = event =&gt; {
        // 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 (
            &lt;ScriptManager
              account={process.env.ANALYTICS_TAG_ACCOUNT}
              profile={process.env.ANALYTICS_TAG_PROFILE}
              environment={process.env.ANALYTICS_TAG_ENV}
            /&gt;
          )
      }
  
      render() {
        return (
          &lt;TrackerProvider.Provider value={
            {
              state: this.state, 
              loadPage: this.pageLoad
            }
          }&gt;
            {this.props.children}
            {this._renderTrackingScript()}
          &lt;/TrackerProvider.Provider&gt;
        )
      }
    }
  
  export default Tracker
  </code></pre>
  
  <p>index.js</p>
  
  <pre><code>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((
  &lt;Tracker&gt;
      &lt;Provider store={store}&gt;
          &lt;Router history={history}&gt;
              &lt;Switch&gt;
                  &lt;Route path={'/analytics'} component={MyComp}  /&gt;
              &lt;/Switch&gt;
          &lt;/Router&gt;
      &lt;/Provider&gt;
  &lt;/Tracker&gt;
  ), document.getElementById('root'))
  </code></pre>
  
  <p>MyComp.js</p>
  
  <pre><code>import React from 'react
  import { TrackerProvider } from '../../lib/tracking/Tracker
  
  const MyComp = () =&gt; {
      return (
          &lt;TrackerProvider.Consumer&gt;
           {context =&gt;
                &lt;&gt;
                  &lt;div&gt;This is my test page for track events for analytics&lt;/div&gt;
                  &lt;button data-analytics="TEST_BUTTON"&gt;Test Analytics&lt;/button&gt;
                &lt;/&gt;
           }
          &lt;/TrackerProvider.Consumer&gt;
      )
  }
  
  export default MyComp
  </code></pre>
  
  <p>Here's what I'm struggling with a little bit:<br />
  1. When I load a nested child component that consumes the context, how do I notify the Parent (<code>&lt;Tracker /&gt;</code>) to trigger some function? Similar to <code>componentDidUpdate</code>.</p>
  
  <p>In essence a user navigates to the <code>MyComp</code> page and the <code>pageLoad</code> function is fired in the <code>Tracker</code>.<br /><br />2. How do I update the Context from <code>MyComp</code> without depending on some click event in the render method to run a funciton. So maybe in <code>componentDidUpdate</code> I can update the context.</p>