1

I'm implementing a ReactJS app which is sending telemetry to App Insights. It's tracking PageViews ok except every PageView has the name "<App Name>" because that's our page title and it does not change between routes (for "reasons"). This makes our App Insights PageView data not as helpful as it could be.

I want to send the current route as the PageView name instead of the page title using a telemetry initializer. Problem is I get an error when I try to use the useLocation hook to get the current route:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

Am using react-dom v17 and react-router-dom v6, so I'm probably "breaking the Rules". I might be using the App Insights SDK incorrectly as well.

Here is my <App /> where I'm currently using App Insights:

import { AppInsightsContext, ReactPlugin, withAITracking } from '@microsoft/applicationinsights-react-js';
import { ApplicationInsights, PageView } from '@microsoft/applicationinsights-web';
//<snip> 

const reactPlugin = new ReactPlugin();
const appInsights = new ApplicationInsights({
    config: {
        connectionString: 'myconnectionstring',
        extensions: [reactPlugin],
        enableAutoRouteTracking: true,
        enableCorsCorrelation: true,
        enableRequestHeaderTracking: true,
        enableResponseHeaderTracking: true,
    },
);
appInsights.addTelemetryInitializer((envelope) => {
    const telemetryItem = envelope.data.baseData;
    if (envelope.name === PageView.envelopeType) {
        const { pathname } = useLocation(); // runtime error
        telemetryItem.name = pathname;
    }
});
appInsights.loadAppInsights();

const App: React.FC = () => {  
    return (
        <Provider store={store}>
            <BrowserRouter>
                <AppInsightsContext.Provider value={reactPlugin}>
                    <AppBootstrap />
                    <ToastContainer />
                </AppInsightsContext.Provider>
            </BrowserRouter>
        </Provider>
    );
};

export default withAITracking(reactPlugin, App);

Any ideas how I might be able to do this? Kinda new to React!

Owen
  • 47
  • 1
  • 7
  • You *are* breaking the rules of hooks. What would be the "normal way" involving the page title? What part of this code needs the `location.pathname`? It looks like it's `appInsights`, but where is `appInsights` used? – Drew Reese Aug 16 '22 at 23:51
  • @DrewReese The "normal way" is to remove the `appInsights.addTelemetryInitializer()` call altogether. Then the app insights SDK's default behaviour takes over and uses the page title as PageView name. Which works just fine too. I guess the ReactPlugin must be what's "using" `appInsights` through the extensions config? It's using the [suggested setup](https://learn.microsoft.com/en-us/azure/azure-monitor/app/javascript-react-plugin) as far as I can tell. – Owen Aug 17 '22 at 00:06
  • What are the "reasons" for not updating the page title dynamically? – Drew Reese Aug 17 '22 at 00:13
  • Business prefers it that way. Obviously if I could change their minds then this problem goes away but that's not the current situation. – Owen Aug 17 '22 at 00:19
  • 1
    Could you use a custom history object that is accessible outside React and set up a `history.listen` callback that updates some global context value that is also accessible from this `addTelemetryInitializer` handler? I'm pretty familiar with RRD, but have absolutely zero familiarity with this telemetry module, so I'm just spitballing ideas how to access the routing context the app is using from outside the app. – Drew Reese Aug 17 '22 at 00:31
  • 1
    I suppose you could also use the `useLocation` hook from within the app to "leak" out location changes to *some* external global variable. I don't highly recommend it, but you could just piggy-back on the `window` object. – Drew Reese Aug 17 '22 at 00:34
  • 1
    Interesting ideas! I see why pushing back on the business might be worth looking into now heh – Owen Aug 17 '22 at 00:41
  • Sure, assert your technical expertise! Worth a shot to push back and inform them of the easy way and you can move on to more important work, or they can pay you to futz about doing it some odd way. – Drew Reese Aug 17 '22 at 00:54

0 Answers0