Posted on • Edited on • Originally published atsergiodxa.com
Feature Flags in React with Flagged
When you are working in a big product, with multiple teams adding features and doing continuos deployment it's common to need a way to hide certain unfinished or unpolished parts of a UI from the users in production.
Or maybe you want to only show certain features to some users, maybe only to paid users or employees of a company. Even it's possible that you want to hide parts of the UI based on the role, e.g. only show admin features to admin users.
This is where enters Feature Flags, a technique to hide or show features based on a flag, which is basically a boolean which tells the application if the feature is enabled or not.
Let's see how we could show or hide React components based on those flags, for doing this we are going to use a package calledFlagged, which is a super tiny library to use this technique in React based applications.
Hide Admin Only Components
Let's start with the simplest one, hide components intended to be available only to admin users. Let's say we have a wiki application, this application shows to the user the content along a button to edit it, but those edits should be moderated and if you are an admin it will show another button to see pending edits.
importReactfrom"react";importEditButtonfrom"./edit-button";importModerateButtonfrom"./moderate-button";functionContentPage({content}){return(<section><header><EditButton/><ModerateButton/></header><article>{content}</article></section>);}exportdefaultContentPage;
Something like that should work, right? But what happens when an non-admin users access a page rendered by this component? It will see two buttons, the edit and the moderate, and if the user tries to click the moderate button it will probably got a rejection when trying to access the moderation page which is probably a protected page already.
This is not ideal from the user perspective, we shouldn't show a button the user can't use, to solve this let's use flagged.
importReactfrom"react";import{FlagsProvider}from"flagged";importContentPagefrom"./content-page";functionApp({user}){return(<FlagsProviderfeatures={{moderate:user.role==="admin"}}><ContentPage/></FlagsProvider>);}exportdefaultApp;
This will make the flagmoderate
enabled if the user has the roleadmin
and disabled in other cases.
Now we need to check the flag status in our component, in our case since we want to hideModerateButton
completely if the user is not admin we could use thewithFeature
high order component flagged gives us.
importReactfrom"react";import{withFeature}from"flagged";importButtonfrom"./button";functionModerateButton(){return<Buttonhref="moderate">Moderate</Button>;}exportdefaultwithFeature("moderate")(ModerateButton);
Now our component will only render if the flagmoderate
istrue
, if it'sfalse
thenwithFeature
will returnnull
and avoid rendering at all.
This is useful in the case we want to render or not a component without a fallback in case the feature is disabled.
Paid Only Feature with Fallback
Let's say now we want to only let paid users be able to edit content in our wiki, while free users will only be able to read the content, we could use an approach similar to before and hide the edit button completely from free users, however in this case it could be better to let the free users know this edit feature exists and they need to pay to use it, this way users may be tempted to pay us.
Let's start by adding a new flag.
importReactfrom"react";import{FlagsProvider}from"flagged";importContentPagefrom"./content-page";functionApp({user}){constfeatures={moderate:user.role==="admin",paid:user.role==="admin"||user.hasActiveSubscription};return(<FlagsProviderfeatures={features}><ContentPage/></FlagsProvider>);}exportdefaultApp;
This will enable thepaid
features if the user is either an admin or has an active subscription.
Now let's use theFeature
component flagged gives use to provide an alternative to the Edit button in case the user is not a paid one.
importReactfrom"react";import{Feature}from"flagged";importEditButtonfrom"./edit-button";importFakeEditButtonfrom"./fake-edit-button";importModerateButtonfrom"./moderate-button";functionContentPage({content}){return(<section><header><Featurename="paid">{isPaid=>(isPaid?<EditButton/>:<FakeEditButton/>)}</Feature><ModerateButton/></header><article>{content}</article></section>);}exportdefaultContentPage;
ThisFeature
component will let use know if the featurepaid
is enabled so we could show two different components based on that. OurFakeEditButton
could simulate theEditButton
and show a modal to convince the user to become a paid one in order to use it.
We could also use theFeature
component to replace thewithFeature
high order component.
importReactfrom"react";import{Feature}from"flagged";importEditButtonfrom"./edit-button";importFakeEditButtonfrom"./fake-edit-button";importModerateButtonfrom"./moderate-button";functionContentPage({content}){return(<section><header><Featurename="paid">{isPaid=>(isPaid?<EditButton/>:<FakeEditButton/>)}</Feature><Featurename="moderate"><ModerateButton/></Feature></header><article>{content}</article></section>);}exportdefaultContentPage;
This way we could ditch thewithFeature
HOC, the only possible issue here is not ourContentPage
needs to know ifModerateButton
should be behind a flag or not, in the HOC approach it was theModerateButton
the only one aware of the flag.
Run Effects Based on a Flag
We saw how to use the high order component and the render prop API Flagged gives us, both of those use internally the custom hookuseFeature
to detect if the feature is enabled or not. This custom hook could also help use create custom logic based on a flag.
Let say now want to track when a free user access a page, but we don't want to track paid users, since they are paying we promising them anonymity in our application.
Let's create a custom hookuseTracking
which will use ouruseFeature
to check if it should or not track the user.
importReactfrom"react";import{pageview}from"../services/analytics";import{useFeature}from"flagged";functionuseTracking(){constisPaid=useFeature("paid");React.useEffect(()=>{if(isPaid)return;pageview(window.location.pathname);},[isPaid]);}exportdefaultuseTracking;
Now let's use it in ourContentPage
component.
importReactfrom"react";import{Feature}from"flagged";importEditButtonfrom"./edit-button";importFakeEditButtonfrom"./fake-edit-button";importModerateButtonfrom"./moderate-button";importuseTrackingfrom"../hooks/use-tracking";functionContentPage({content}){useTracking();return(<section><header><Featurename="paid">{isPaid=>(isPaid?<EditButton/>:<FakeEditButton/>)}</Feature><ModerateButton/></header><article>{content}</article></section>);}exportdefaultContentPage;
That's all, our tracking hook will only work for non-paid users.
Hooks as a Low Level Primitive
We could also use theuseFeature
hook to replace the render prop component inContentPage
.
importReactfrom"react";import{useFeature}from"flagged";importEditButtonfrom"./edit-button";importFakeEditButtonfrom"./fake-edit-button";importModerateButtonfrom"./moderate-button";importuseTrackingfrom"../hooks/use-tracking";functionContentPage({content}){constisPaid=useFeature("paid");useTracking();return(<section><header>{isPaid?<EditButton/>:<FakeEditButton/>}<ModerateButton/></header><article>{content}</article></section>);}exportdefaultContentPage;
Even theModerateButton
could be hidden using theuseFeature
hook.
importReactfrom"react";import{useFeature}from"flagged";importEditButtonfrom"./edit-button";importFakeEditButtonfrom"./fake-edit-button";importModerateButtonfrom"./moderate-button";importuseTrackingfrom"../hooks/use-tracking";functionContentPage({content}){constisPaid=useFeature("paid");constisModerator=useFeature("moderate");useTracking();return(<section><header>{isPaid?<EditButton/>:<FakeEditButton/>}{isModerator&&<ModerateButton/>}</header><article>{content}</article></section>);}exportdefaultContentPage;
This will renderModerateButton
only ifisModerator
istrue
.
Final Words
As you could see above there are multiple cases in which feature flags flags is useful and withFlagged there are multiple approaches you could take to detect if a flag is enabled and render a component or run an effect.
Are you using feature flags in your project? Do you know another example where it could be useful? Do you have any question about how Flagged or Feature Flags works? Let a comment below to share your thoughts.
Top comments(2)

Nice article, thank you. I do a question - what benefit does it provide over using the built in context? You can just as easily pass those feature flags with regular correct, and consume them withuseContext
.

Flagged uses context internally, also checks you are passing an array or object and gives you the provider, the hook, the HOC and the render prop versions, along with types of you use TypeScript and has test to ensure you it will work without you needing to code it
For further actions, you may consider blocking this person and/orreporting abuse