DEV Community

Cover image for 🏗️ How to rollout features to specific users in ReactJS
Andy
Andy

Posted on

🏗️ How to rollout features to specific users in ReactJS

TL;DR

In this article I am going to show you how to activate specific features for specific users using feature flags in a ReactJS app.

Even though there are multiple services which would allow you to manage your feature flags, we are going to use SwitchFeat, a service that I am building open-source and in public.

Why is this useful?

  • Gradually release features to subsets of users.
  • Decouple deployments from releases.
  • Safe guarding new feature with kill-switches.
  • and many more...

Can you help?

I am trying to increase the visibility of my repo, could you help me by adding a star to the project? It would help me so much and it would give a big boost to publish more articles weekly! 🤩

https://github.com/switchfeat-com/switchfeat


Let's get started! 🔥

First thing first, create a React app in Typescript

npx create-react-app my-react-app --template typescript

Let's install some common dependancies

npm i --save @types/node @types/react @types/react-dom uuidv4

Running these two commands already give you a working React app which we can start modifying as desired.

This is the default App.tsx which is going to hold our homepage:

const App : React.FC = () => {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Which looks like this:

Default result

To manage styles a bit more easily, we will use TailwindCSS, which allows to specify inline classes without going to touch css files.

I know this stuff Andy! Give me something new!


Let's protect our component ⛔

Now things become a bit more interesting. We are going to build a new component, SuperCoolCard, which is going to hold some functionality which we want to gate and make available only to a specific segment of users.

Let's say that we want to show this card to users with an email address ending with @switchfeat.com.

For the purpose of this article, the component is going to be super simple:

export const SuperCoolCard : React.FC = () => {
    return (
        <div className="rounded-lg shadow   
             bg-orange-500 p-10 mt-10">
            <div>Super cool feature </div>
            <button className="rounded-md bg-indigo-600 
                    px-3.5 py-2.5 font-semibold text-white 
                    shadow-sm hover:bg-indigo-500 
                    text-lg mt-4">Let's start</button>
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

In order to gate the access to this component to a specific user segment, we can use the SwitchFeat API as follows:

 const [showNewCard, setShowNewCard] = useState<boolean>(false);
 const [userContext, setUserContext] = 
                   useState<{}>({ username: 'a@switchfeat.com' });

 useEffect(() => 
    const formData = new FormData();
    formData.append('flagKey', "new-card");
    formData.append('flagContext',  JSON.stringify(userContext));
    formData.append('correlationId', uuidv4());

    const evaluateFlag = () => {
      fetch(`http://localhost:4000/api/sdk/flag/`, {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Access-Control-Allow-Credentials": "true",
          "Access-Control-Allow-Origin": "true"
        },
        body: formData
      }).then(resp => {
        return resp.json();
      }).then(respJson => {
        setShowNewCard(respJson.data.match);
      }).catch(error => { console.log(error); });
    };

    evaluateFlag();

  }, []);
Enter fullscreen mode Exit fullscreen mode

First of all, we add a state to the page which will hold the information regarding if the card component should be shown or not.
This is a React construct which forces a re-render of the component if such state changes, to show the latest data.

The useEffect() call is a side effect which, in this case, gets executed at first page load (or page refreshes). It is responsible of calling the SwitchFeat API via a POST Fetch request, to get the status of the requested flag based on the provided context.

In this example, the user context provided is: {email:'a@switchfeat.com'}.

For the purpose of this article, I put the user context in the state of the component, but this should really depend on the current user data in a real scenario.

Last step is going to beadding the reference to the new component in the page behind the "protected" state:

return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"  href="https://reactjs.org"
          target="_blank" rel="noopener noreferrer">Learn React
        </a> 
        {showNewCard && <SuperCoolCard />}
      </header>
    </div>
  );
Enter fullscreen mode Exit fullscreen mode

What's going to happen now, is that when there is a state change in the value of showNewCard, the whole component re-renders and the SuperCoolCard component will either show up or not based on the API response from SwitchFeat. Cool right!?

SwitchFeat is under active development and I already planned to release an SDK for NodeJS, together with other languages over time. So the interaction with the API will be simplified even further.


Behind the scenes 😎

The SwitchFeat API, upon receiving the request, runs the following checks:

  • Checks if the requested flagKey points to an existing flag.
  • Checks if the requested flag has any rule.
  • Evaluates all available rules and checks if the provided context (in this case {email:'a@switchfeat.com'}), matches at least one segment condition.
  • Returns the match result or an error.

The final results 🚀

Here it is how the page looks like by default having the flag disabled.

Result with disabled flag

Instead when the flag is enabled and there is a rule matching the context, our beautiful card can shine on the homepage!

Result with enabled flag

What's even more important is that even if the flag stays enabled, but the context of the API call changes to something which is not matching any of the flag rules, the card will be removed from the DOM for those users.

So for example, providing a context like: {email:'a@google.com'}, the result is going to be:

Result with no matching rule flag


Well done! 🙌

You can now sit and relax knowing that any feature you want to silently deploy and release at your own time, are safely protected by your feature flags!


So.. Can you help? 😉

I hope this article was somehow interesting. If you could give a star to my repo would really make my day!

https://github.com/switchfeat-com/switchfeat

Top comments (0)