ololo
ololo

Reputation: 2076

How to properly wrap a Functional Component into a React HOC

I am building some web pages in nextjs and I need to make sure certain pages can only be accessed if the user has been authenticated as below:

import UserManager from "../managers/user_manager";
import { useRouter } from "next/router";
import LogInPage from "../pages/auth/login";

export default function EnsureAuthenticated(OriginalComponent) {
    const router = useRouter();
    const loggedInUser = UserManager.getLoggedInUser();
    if (loggedInUser ) {
        return <OriginalComponent />;
    }
    return router.push(LogInPage.routePath);
}

And here is my dashboard page that I need to wrap with the above HOC to enforce authentication

import { useEffect } from "react";
import { useRouter } from "next/router";
import EnsureAuthenticated from "../../components/auth_hoc";

function DashboardHomePage(props) {
    const router = useRouter();
    return (<div>
        Home Page
    </div>);
}
DashboardHomePage.routePath = "/dashboard/home";
export default EnsureAuthenticated();

Unfortunately for me I keep getting this error after compiling in NextJS

Error: 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.

Please, how do I resolve this? Thank you.

Upvotes: 0

Views: 1264

Answers (1)

Anish Antony
Anish Antony

Reputation: 1525

You aren't passing DashboardHomepage component to HOC . HOC code has to changed , we cannot use hooks in HOC body because we are calling HOC as a function instead of a component. When we call a component as a function react excludes all the lifecycles from that.

There is also an issue with the usage of router in your code, as in nextjs if we use it in render it will be rendered and client side and server side. You may have to create a component which will do routing in useEffect and use it instead of router.push(LogInPage.routePath)

import React from "react";
import UserManager from "../managers/user_manager";
import { useRouter } from "next/router";
import LogInPage from "../pages/auth/login";

export default function EnsureAuthenticated(OriginalComponent) {
  return (props) => {
    const router = useRouter();
const loggedInUser = UserManager.getLoggedInUser();
    if (loggedInUser ) {
        return <OriginalComponent />;
    }
//below code can give error as router is supposed to be called only at client side, you might have to implement it using useEffect
    return router.push(LogInPage.routePath);
  };
}

import { useRouter } from "next/router";
import EnsureAuthenticated from "../components/test/AddCount";

function DashboardHomePage(props) {
  const router = useRouter();
  return <div>Home Page</div>;
}

DashboardHomePage.routePath = "/dashboard/home";

export default EnsureAuthenticated(DashboardHomePage);

Upvotes: 1

Related Questions