DEV Community

Cover image for React HOC to make components permission driven
Imanshu Rathore
Imanshu Rathore

Posted on

React HOC to make components permission driven

This is a design pattern which I’ve used in most of my React applications to limit the access level of components.

Before diving deep into the solution, let’s first understand what a High Order Component (HOC) is ?

HOC is an advanced technique in React for reusing component logic. They are a pattern that is based upon the concept of High Order Functions in JavaScript. In layman terms, a HOC is a function that takes a component and returns a new component. It is not a part of React API but simple fact is that it emerges from React’s compositional nature.

In this solution, I’m going to use following functionalities to achieve the end result:

  • React: version ≥ 16.8
  • JavaScript
  • Global State Management: To store the user permissions and pass it down through the component tree. I’ll be using Context-Reducer, you can use any other library also such as Redux, MobX or Zustand etc.

Solution:

To start, let us assume that we have an application where we need to limit our application’s component access level based upon particular user’s permission.

  • Initially, we have 4 components:

Component1 : should be accessible if user has ACCESS_COMPONENT1 permission.

import React from "react";

const Component1 = (props) => {
  return (
    <p>Component only accessible if user has ACCESS_COMPONENT1 permission</p>
  );
};

export default Component1;
Enter fullscreen mode Exit fullscreen mode

Component2 : should be accessible if user has ACCESS_COMPONENT2 permission.

import React from "react";

const Component2 = (props) => {
  return (
    <p>Component only accessible if user has ACCESS_COMPONENT2 permission</p>
  );
};

export default Component2;
Enter fullscreen mode Exit fullscreen mode

Component3 : should be accessible if user has ACCESS_COMPONENT3 permission.

import React from "react";

const Component3 = (props) => {
  return (
    <p>Component only accessible if user has ACCESS_COMPONENT3 permission</p>
  );
};

export default Component3;
Enter fullscreen mode Exit fullscreen mode

App : parent wrapper which imports the above 3 components

import React from "react";
import Component1 from './Component1';
import Component2 from './Component2';
import Component3 from './Component3';

const App = (props) => {
  return (
    <div>
      <Component1 />
      <Component2 />
      <Component3 />
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode
  • Let us create a component UserPermissionProvider which will fetch the user permissions from some API, store it and make it available to its children. It will also export UserPermissionStore context that we can consume in our component tree to access the store.

Note: I’ll be hardcoding the permissions in this example

import React, { createContext, useState, useEffect } from "react";

export const UserPermissionStore = createContext({ userPermission: {} });

const UserPermissionProvider = (props) => {
  const { children } = props;
  const [userPermission, setUserPermission] = useState({});

  useEffect(() => {
    const permissions = {
      ACCESS_COMPONENT1: "ACCESS_COMPONENT1",
      ACCESS_COMPONENT2: "ACCESS_COMPONENT2",
      ACCESS_COMPONENT3: "ACCESS_COMPONENT3",
    };
    setUserPermission(permissions);
  }, []);

  return (
    <UserPermissionStore.Provider value={{ userPermission }}>
      {children}
    </UserPermissionStore.Provider>
  );
};

export default UserPermissionProvider;
Enter fullscreen mode Exit fullscreen mode
  • We will now pass our App component as a child within UserPermissionProvider component so that our App component tree has access to UserPermissionStore context.
import React from "react";
import Component1 from "./Component1";
import Component2 from "./Component2";
import Component3 from "./Component3";
import UserPermissionProvider from "./UserPermissionProvider";

const App = (props) => {
  return (
    <UserPermissionProvider>
      <div>
        <Component1 />
        <Component2 />
        <Component3 />
      </div>
    </UserPermissionProvider>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode
  • Now we will create a HOC withUserPermission that will take a Component and the permission required to access that Component as input. It will return the Component if supplied permission is valid otherwise nothing is returned.
import React, { useContext } from "react";
import { UserPermissionStore } from "./UserPermissionProvider";

const withUserPermission = (Component, requiredPermission) => (props) => {
  const { userPermission } = useContext(UserPermissionStore);

  if (!userPermission[requiredPermission]) return null;

  return <Component {...props} />;
};

export default withUserPermission;
Enter fullscreen mode Exit fullscreen mode
  • We will create our new enhanced components using withUserPermission HOC which will be only accessible if the permission needed to access them is available in user permissions.
import React from "react";
import withUserPermission from "./withUserPermission";

const Component1: React.FC = (props) => {
  return (
    <p>Component only accessible if user has ACCESS_COMPONENT1 permission</p>
  );
};

export default withUserPermission(Component1, 'ACCESS_COMPONENT1');
Enter fullscreen mode Exit fullscreen mode

Note: Similarly we will update our Component2 and Component3 as well with their respective permissions.

I have tried to explain the best method that I know. If you know others, share in the comments for everyone!

Thanks For Reading, Follow Me For More

Top comments (0)