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
UserPermissionProvider
which will fetch the user permissions from some API, store it and make it available to its children. It will also exportUserPermissionStore
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;
- We will now pass our
App
component as a child withinUserPermissionProvider
component so that our App component tree has access toUserPermissionStore
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;
- 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;
- 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');
Note: Similarly we will update our Component2 and Component3 as well with their respective permissions.
Top comments (0)