简体   繁体   中英

Tutorial uses a React Hook, but I'm working in a Class Component setting

I'm trying to follow this tutorial to implement Google Analytics with pageview tracking in my React application. However, the tutorial uses a React hook, while I've set up my application using class components. I've unsuccesful to translate the tuturial to a class setting. How should I adjust to make this work for my use case?

Routes page, \src\pages\index.js:

// the function of concern
import useGaTracker from "../useGaTracker";

class Base extends Component {
    render() {
        useGaTracker();
        // The hook inside a Class component, which is not allowed.
        // But how can I make it work in my class components setting?

        function withProps(Component, props) {
            return function (matchProps) {
                return <Component {...props} {...matchProps} />;
            };
        }

        return (
            <Router history={history}>
                <Switch>
                    <Route exact path="/" component={Homepage} />
                    // Etc.

GA function, \src\useGaTracker.js:

import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga";

const useGaTracker = () => {
    const location = useLocation();
    const [initialized, setInitialized] = useState(false);

    useEffect(() => {
        ReactGA.initialize(process.env.REACT_APP_GA_TAG);
        setInitialized(true);
    }, []);

    useEffect(() => {
        if (initialized) {
            ReactGA.pageview(window.location.pathname + window.location.search);
        }
    }, [initialized, location]);
};

export default useGaTracker;

And \src\index.js:

import Base from "./pages";

render(
    <Provider store={store}>
        <BrowserRouter>
            <Base />
        </BrowserRouter>
    </Provider>,
    document.getElementById("root")
);

Calling upon the GA function inside he Base class produces the error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

How should I rewrite this to make it work in my Class components setting?

You could make a higher-order component create a functional component, and have that one call useGaTracker before rendering the given non-functional Component:

const withGaTracker = (Component) => {
  return (props) => {
    useGaTracker();
    return (
      <Component {...props} />
    );
  };
};

Then pass in the Base component

const BaseWithGaTracker = withGaTracker(Base);

and render the result in your index.js by replacing <Base /> with <BaseWithGaTracker /> .


edit: Simpler yet, just make a single functional component that calls the hook and renders its children:

const GaTracker = ({children}) => {
  useGaTracker();
  return children;
}

then wrap that around <Base /> in index.js

<GaTracker>
  <Base />
</GaTracker>

If you're not gonna use that hook anywhere else, you could also just inline it in the new component.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM