javascriptreactjslaunchdarkly

Accessing LaunchDarkly flags from React.JS


I am trying to access LaunchDarkly flags from my App context. The code looks like:

import { useState, useEffect } from 'react';
import { Helmet } from 'react-helmet';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import DateFnsUtils from '@date-io/date-fns';
import { ApolloProvider } from 'react-apollo';
import { Route, Router, Switch } from 'react-router-dom';
import { withLDProvider } from 'launchdarkly-react-client-sdk';
import { Loading } from '@ap/owl-ui-controls';
import { useAuth0 } from './context/Authentication';
import LabelContext from './context/LabelContext';
import { CommunityByNameContext } from './context/CommunityByNameContext';
import { segment_init } from './utils/segment';
import withConfig, { ConfigEnum } from './utils/withConfig';
import client from './utils/graphQLClient';
import labels from './config/labels';
import CurrentUser from './services/CurrentUser';
import Layout from './Layout';
import history from './utils/history';
import { SearchCommunity } from './common/Filters/SearchNameFilter/findCommunitiesQuery';
import AmplitudeContext, { AmplitudeData } from './context/AmplitudeContext';
import { DisclosuresContextProvider } from './context/DisclosuresContext';
import placeService from './services/placesService';
import { FeaturedCommunitiesIdsProvider } from './context/FeaturedCommunitiesIdsContext';
import { optimizelyInit } from './utils/optimizely';
import { FamilyFileContextProvider } from './context/FamilyFileContext';

const segmentKey = withConfig(ConfigEnum.SEGMENT_KEY);
const currentUserString = localStorage.getItem('CURRENT_USER');

const App = () => {
  const { loading } = useAuth0();
  const [currentUser, setCurrentUser] = useState(currentUserString ? JSON.parse(currentUserString) : null);
  const [communityByName, setCommunityByName] = useState<SearchCommunity | null>(null);
  const [amplitude, setAmplitude] = useState<AmplitudeData>({});

  useEffect(() => {
    placeService.init();
  }, []);

  if (loading) {
    return <Loading />;
  }

  return (
    <>
      <Helmet>
        <title>Beacon</title>
        <script type="text/javascript">{optimizelyInit(flags)}</script>
        <script type="text/javascript">{segment_init(segmentKey, currentUser)}</script>
      </Helmet>
      <LabelContext.Provider value={labels}>
        <CommunityByNameContext.Provider value={{ communityByName, setCommunityByName }}>
          <FeaturedCommunitiesIdsProvider>
            <AmplitudeContext.Provider value={{ amplitude, setAmplitude }}>
              <MuiPickersUtilsProvider utils={DateFnsUtils}>
                <ApolloProvider client={client}>
                  {/* @ts-ignore */}
                  <CurrentUser onUserChanged={(currentUser: any) => setCurrentUser(currentUser)}>
                    <FamilyFileContextProvider>
                      <DisclosuresContextProvider>
                        <Router history={history}>
                          <Switch>
                            <Route path="/communities" component={Layout} />
                          </Switch>
                        </Router>
                      </DisclosuresContextProvider>
                    </FamilyFileContextProvider>
                  </CurrentUser>
                </ApolloProvider>
              </MuiPickersUtilsProvider>
            </AmplitudeContext.Provider>
          </FeaturedCommunitiesIdsProvider>
        </CommunityByNameContext.Provider>
      </LabelContext.Provider>
    </>
  );
};

export default withLDProvider({
  clientSideID: withConfig(ConfigEnum.LD_CLIENT_SIDE_ID),
})(App);

My nested components, like for example <CurrentUser /> get LD flags, and I am able to access them as:

const CurrentUser = ({ children, flags, onUserChanged })

However, I also need LD flags inside <App /> so I could do:

  <Helmet>
    <title>Beacon</title>
    {flags.optimizely && <script type="text/javascript">{optimizelyInit(flags)}</script>}
    <script type="text/javascript">{segment_init(segmentKey, currentUser)}</script>
  </Helmet>

I have tried accessing flags with const App = ({ flags }), but the value is always undefined.

I even tried sticking the below into a component

const DocumentHead = ({ flags, segmentKey, currentUser }) => (
  <Helmet>
    <title>Beacon</title>
    <script type="text/javascript">{optimizelyInit(flags)}</script>
    <script type="text/javascript">{segment_init(segmentKey, currentUser)}</script>
  </Helmet>
);

Flags are still undefined.

Suggestions?


Solution

  • Apparently, there is a useFlags hook. We can get flags as:

    const flags = useFlags();
    

    This can be called from the <App /> component.