reactjsuse-contexthigher-order-components

How to create HOC to wrap useContext provider in React?


I want to reuse a context provider in different parts of my app using HOC ("higher order components"), but my state does not get updated.

This is the wrapper of the provider.

import React, { FC, useState } from "react";
import AdminContext from "./adminContext";

const AdminContextWrapper: FC = ({ children }) => {
  const [authAdmin, setAuthAdmin] = useState<boolean | null>(null);
  
  const value = { authAdmin, setAuthAdmin };
  return (
    <AdminContext.Provider value={value}>{children}</AdminContext.Provider>
  );
};

export default AdminContextWrapper;

This is how I am implementing it :

import { useContext } from "react";
import AdminContext from "@comp/contexts/adminContext";
import AdminLogin from "@comp/admin/adminLogin";
import Limit from "@comp/admin/limits";
import AdminContextWrapper from "@comp/contexts/adminWrapper";

const Admin = () => {
  const { authAdmin } = useContext(AdminContext);

  const AdminPage = () => {
    return (
      <div>
        <Limit />
      </div>
    );
  };

  return (
    <AdminContextWrapper>
      {authAdmin ? <AdminPage /> : <AdminLogin />}
    </AdminContextWrapper>
  );

Finally, this is my context:

import { createContext } from "react";
import { AdminContextType } from "@comp/utils/types";

const InitialUserContext: AdminContextType = {
  
  authAdmin: false,
  setAuthAdmin: (authAdmin: boolean | null) => {},
  
};

const AdminContext = createContext<AdminContextType>(InitialUserContext);

export default AdminContext;

I can see the state change in the login page but the admin page is not getting the update.

adminLogin.tsx

//...
 const { setAuthAdmin, authAdmin } = useContext(AdminContext);

 useEffect(() => {
    console.log(authAdmin); // returns true after validating but the admin does not update.
  }, [authAdmin]);
//...

I highly appreciate any help. Thank you.


Solution

  • Unless I'm misreading things, in

    const Admin = () => {
      const { authAdmin } = useContext(AdminContext);
      // ...
      return (
        <AdminContextWrapper>
          {authAdmin ? <AdminPage /> : <AdminLogin />}
        </AdminContextWrapper>
      );
    }
    

    you're trying to use the context outside its provider AdminContextWrapper - useContext would return undefined there unless you're already nested within another provider for the admin context, in which case the inner AdminContextWrapper there would give the inner components a different admin context.

    You may want to make sure there's only ever exactly one admin context.

    (As an aside, the // ... above used to be a nested component in your original code. Never do that – nested components' identity changes on each update, causing spurious re-renders.)