Hello folks,
Almost in every app, we encounter situations where we need to render components or elements conditionally. If a user is logged in, the show user her profile else ask her to login, if the user is admin, show him admin pages etc. are just a few scenarios out of them. The most common practice for such use cases is use of if-else, ternary operators, && operators or switch cases.
Though these are simple to use options, at times, they may make your code messier. Today let’s cover two ways which are very effective and cleaner in terms of handling situations like this.
Using Enum
Let’s consider a scenario, where you want to display a settings page of your app based on the user role. The conditions here are,
- If the user is admin, show her admin settings page.
- If the user is not admin, show user settings page.
- If the user is a guest, ask her to login to get her role.
Simple enough! Apart from this, let's also print the username on their respective pages. (This is just to understand how we can pass props to the components). I have created two different components, AdminSettings and UserSettings with some list items to replicate the real world component.
Both the component are as below -
const AdminSettings = ({ username }) => {
return (
<>
<p>Hello {username}</p>
<ul>
<li>Admin Settings Option 1</li>
<li>Admin Settings Option 2</li>
<li>Admin Settings Option 3</li>
</ul>
</>
);
};
const UserSettings = ({ username }) => {
return (
<>
<p>Hello {username}</p>
<ul>
<li>User Settings Option 1</li>
<li>User Settings Option 2</li>
<li>User Settings Option 3</li>
</ul>
</>
);
};
Now let’s understand the conditional rendering. We will have one outer settings component, which will get both username and userRole. Using these two options we can decide which setting component to render. This outer settings component will have all the logic of this conditional rendering. Let’s first see the settings component and then understand the enum and conditional rendering.
const Settings = (props) => {
const { userRole, username } = props;
const roleSettings = (username) => ({
admin: <AdminSettings username={username} />,
user: <UserSettings username={username} />,
guest: <p>Hello, you will need to login first!!</p>,
});
return (
<div>
<h1>Settings</h1>
<p>{roleSettings(username)[userRole]}</p>
</div>
);
};
export default Settings;
In the above code, the roleSettings function is considered as enum. Basically, it is just returning an object with different components. Hence in the return statement, we are actually trying to render one key of that object which matches the userRole. As that key contains the component, our required component will get rendered correctly.
As roleSettings is a function, the whole conditional rendering becomes very clean and easy to implement. Also, you don't need to hardcode many values in your application. You can pass props down to the components using the same function.
Apart from enum, other effective way is using HOC (Higher Order Component).
Using HOC
Higher Order Components in React are the wrapper components which takes the component as an argument and returns a component. Higher order components are considered very effective when working on role based access control systems. Though that is out of scope for this article, I will surely try to cover it in some of my next articles.
For now, just to give you a small example of HOC used for conditional rendering, lets consider the same use-case and use a HOC to show logged-in user.
The HOC will look like this -
function withLogin(Component) {
return function EnhancedComponent({ isLoggedIn, ...props }) {
if (isLoggedIn) {
return <Component {...props} />;
}
return (
<div>
<p>Hello, please login to see your profile!</p>
</div>
);
};
}
const ShowProfile = withLogin(Profile);
function App({ profile, isLoggedIn }) {
return (
<div>
<h1>Hello Conditional Rendering</h1>
<ShowProfile isLoggedIn={isLoggedIn} profile={profile} />
</div>
);
}
If you check the code, withLogin is a Higher Order Component, which will return detailed profile or settings page, if the user is logged in, else it will just return a message asking user to login.
We can use similar HOC for loaders or more complex permission based use-cases, which we will be covering in our next article.
If you are using more effective ways of conditional rendering or some different use-cases for HOCs, do share them with me in comments!
You can also connect with me on Twitter or buy me a coffee if you like my articles.
Keep learning!
Latest comments (33)
Wow, even the comments section has great information! Thanks everyone!
How about this ?
see babel-plugin-react-directive
This remains me the Vue.js code
If it is easy to use, why not?
Enums are very powerful and restrict the keys that can be used.
For clarity, the
roleSettingsfunction returns a hashmap (key/value pairs). It is not an enum.Thx for sharing two cool approaches to conditional renderings.
To validate the
userRoleand provide a fallback toguest, I recommend this:Really great points!
A nice addition would be to add in the mix the Lazy loading, this way a user with role A won’t even have a link to receive bundles that won’t be meant for them ;)
The best way is to use switch case statement to avoid constructing the other components. Otherwise, good article. Thanks
I've used HOCs before, but nowadays I'm trying to avoid them. I'm trying to keep my code small, simple, readable. This would be my solution.
That it needs an extra tool (TS) to make it somewhat useable imo already validates my concern. You still cannot SEE from the code what it is.
Why is it so obvious that all components will receive the same prop always? Even in the example there is the logged out case which makes this invalid. Sure, it works fine until I need more/different props, but why would I settle down with a solution that doesn't let me modify later? Especially when the other solution doesn't cost me any extra effort over the enum one.
Default is not my concern at all, it can be replaced with
case 'guest'. My problem is using an enum:foo: <Bar />): it has performance costsfoo: Bar): it sacrifices flexibility and maintainability.The last example you wrote is also an anti-pattern I explained.
As a hint, this code snippet alone here should be a red flag in the 90% of the cases:
<Component {...props} />. By seeing the code you don't know what your component exactly is, and what props it is getting. This could be the equivalent of TS's any in React.For many conditional rendering cases I really like jsx-control-statements (specifically If and Choose)
npmjs.com/package/babel-plugin-jsx...
Great Post! Saved it for future implementations :D
Thank you 🙌
Some comments may only be visible to logged-in visitors. Sign in to view all comments.