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;
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;
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;
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;
- Let us create a component
UserPermissionProviderwhich will fetch the user permissions from some API, store it and make it available to its children. It will also exportUserPermissionStorecontext 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;
- We will now pass our
Appcomponent as a child withinUserPermissionProvidercomponent so that our App component tree has access toUserPermissionStorecontext.
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;
- Now we will create a HOC
withUserPermissionthat 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;
- We will create our new enhanced components using
withUserPermissionHOC 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');
Note: Similarly we will update our Component2 and Component3 as well with their respective permissions.
Top comments (0)