DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Mastering React App Configuration With Webpack
  • How to Build a React Native Chat App for Android
  • Leveraging Feature Flags With IBM Cloud App Configuration in React Applications
  • Optimizing User Experience in React Native

Trending

  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  • Docker Model Runner: Streamlining AI Deployment for Developers
  • Contextual AI Integration for Agile Product Teams
  • AI’s Role in Everyday Development
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Implementing Feature Flags in Single-Page Apps With React and Redux Saga

Implementing Feature Flags in Single-Page Apps With React and Redux Saga

Although SPAs are the new norm for modern applications, they introduce new complexities in controlling access to front-end features — specifically, via feature flags.

By 
Justin Baker user avatar
Justin Baker
·
Feb. 16, 17 · Opinion
Likes (3)
Comment
Save
Tweet
Share
7.5K Views

Join the DZone community and get the full member experience.

Join For Free

Built on frameworks like React, Angular, and Ember, single-page apps (SPA) are becoming the new norm for modern applications. They center around dynamically updating a single HTML page via AJAX and HTML5 to deliver a more fluid and faster user experience. This introduces some new complexity when it comes to controlling access to front-end features, specifically via feature flags.

Feature flags (toggles) are used to gate access to particular code snippets, allowing you to control a feature’s rollout, target specific users, and kill a feature in production. The challenge with feature flagging single-page apps is handling the state transformations (the changes in a webpage’s DOM) in a way that maintains performance and a fluid user experience.

This article discusses how to feature flag in a React single-page app to show best practices. More specifically, we demonstrate feature flagging using LaunchDarkly’s JavaScript SDK.

Feature Flagging in Single-Page Apps

With the help of React Router, creating a single-page application can be a very quick and easy process, allowing developers to minimize risk and test features without degrading the user experience. We use Redux Sagas to handle asynchronous actions, which is perfect for integrating our app with the LaunchDarkly JavaScript SDK.

Feature Flags

In our app, we use two feature flags: user-type and header-bar-color. The user-type feature flag controls the content that is displaying depending on the group of current logged in user, while header-bar-color returns a hex code to toggle the color of the navigation bar.

An implementation of header-bar-color might look something like this:

LaunchDarkly Feature Flag with Custom Rules

Integrating Feature Flags With Redux Sagas

We handle the asynchronous process of requesting a LaunchDarkly feature flag by using Redux Sagas. The workflow begins in the App component of our SPA, where we dispatch an action to initialize the LaunchDarkly client.

Then, we can use a saga as middleware to wait for an initialization request to be received, using redux-saga’s takeEvery module, which will call an effect, initLD.

/app/sagas / index.js
export function* watchInitLD() {
    yield takeEvery(LD_INIT_REQUEST, initLD)
}

The effect will call getLD, a function that creates a promise, waiting for the LaunchDarkly client to be ready for flag requests. Since the user is anonymous, we can generate a random token to be used as their key.

/app/sagas / index.js
export function* initLD() {
    let user = {
        key: Math.random().toString(36).substring(7),
        anonymous: true
    }
    ld = ldClient.initialize(YOUR_ENVIRONMENT_KEY, user)
    const flag = yield call(getLD, user)
    yield put({
        type: LD_INIT,
        ld: ld,
        flag: flag
    })
}

function getLD() {
    var ldPromise = Promise.promisify(ld.on)
    return ldPromise('ready').then(function() {
        return ld.allFlags()
    })
}

Once the client is ready, the effect will send the action off to our reducer, to store the client and current feature flag state in props.

/app/reducers / index.js

function reducer(state = initialState, action) {
    switch (action.type) {
        case LD_INIT:
            return { ...state,
                ld: action.ld,
                flag: action.flag,
                headerColor: action.headerColor
            }…
        default:
            return state
    }

Now that the LD client is initialized, and stored in our props, we can define a process to update our flag whenever the current user changes (logging in or out, for example). We take advantage of the fact that we’re already using sagas to asynchronously handle user authentication. When logging in, the authorize effect is called to ensure the login data is correct. When authorization is complete, we’ll make a call to idLD. This will identify a new user in our LaunchDarkly client, and send the correct flag to the reducer for our newly logged in user. Logging out works in a similar fashion. (Note: We make use of some utility functions defined in auth, which return user information from our local storage.)

/app/sagas / index.js
export function* authorize({
    username,
    password,
    isRegistering
}) {
    try {
        ...
    } catch (error) {
        ...
    } finally {
        // When done, we tell Redux we're not in the middle of a request any more and
        // update the feature flag
        let user = {
            key: auth.getToken(),
            custom: {
                groups: auth.getGroup()
            },
            anonymous: false
        }
        let flags = yield call(idLD, user)
        console.log(flags['header-bar-color'])
        yield put({
            type: SENDING_REQUEST,
            sending: false,
            flag: flags['user-type'],
            headerColor: flags['header-bar-color']
        })
    }
}

function idLD(user) {
    var ldPromise = Promise.promisify(ld.identify)
    return ldPromise(user, null).then(function() {
        return ld.allFlags()
    })
}

So, what do we do with the flags stored in our props? Well, in our Home component, we’ll render a different page depending on the flag that was received. In our case, if a fallback flag is received, the “Anonymous” page will be shown no matter who is logged in.

/app/components/Home.js
class Home extends Component {
  render () {
    switch(this.props.data.flag) {
      case 2: 
        return(<Admin />)
      case 1: 
        return(<User />)
      case 0:
      default: 
        return(<Anonymous />)
    }
  }
}

Meanwhile, every time a page is loaded, the Nav component takes in the  headerColor  prop and changes the background of our navbar to said color.

What’s Next?

There are many ways to feature flag within a single-page app, depending on your case and the complexity of your features. 

You can also check out this repo by TrueCar, which provides another avenue for feature flagging in React Redux.

Want to try out this feature flagging in React for yourself? Check out the open source repo!

app React (JavaScript library) feature flag

Published at DZone with permission of Justin Baker, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Mastering React App Configuration With Webpack
  • How to Build a React Native Chat App for Android
  • Leveraging Feature Flags With IBM Cloud App Configuration in React Applications
  • Optimizing User Experience in React Native

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!