In the last project I worked on, some parts in the page should only be shown to privileged users. As easy as it would be to just add that bit of logic in a
render method, it would not be idiomatic React, and it would also get cumbersome when the validation logic becomes more complex, besides the fact that we would have to add similar logic in many places in the code. DRY, as they say.
React makes it easy to solve that situation by making a component that can wrap any part of the app to hide it from unprivileged eyes.
This is the simple solution I’ve been using for that purpose instead:
When this component mounts, it sets
state.admin to the value of the
isAdmin function. If
state.admin is false,
render will only render an empty
<div /> element. Otherwise it will render the
At this point, we could simply do
return children and hope for the best. It may even seem to work in simple cases, but it will explode in our faces if we use React-based UI frameworks like Material-UI. That’s because these frameworks may be passing specific props to nested components in order to render them properly, and putting an
PrivilegedContent in between these nested components will cut the flow of
props being passed down.
In order to render the children properly, we have to make sure that any props passed to
PrivilegedContent also get passed to the component it wraps. For this, we first verify that our component only has one child by using React.Children.only, which “Verifies that children has only one child (a React element) and returns it. Otherwise this method throws an error”. Then we clone our
children and append the props passed to
PrivilegedContent to the first (and only child) using React.Children.map.
At this point,
childrenWithProps is a clone of our children structure with added props that were passed to our
You can use it like this:
There are several improvements that can be done to
PrivilegedContent. Here are some ideas:
- We could pass the validation function (
isAdminin the code above) as a prop to make the component more flexible. In case there is no validation prop, it can use one by default.
- The validation function should probably be asynchronous. In our example we use a synchronous
isAdminfunction, but if we need to contact a server for validation, for example, our code above won’t work.
- The user could pass an extra
placeholderContentprop that the component uses when it doesn’t pass validation, instead of using a generic _div_ tag like it does now.
Can you think of more improvements? Let me know in the comments!