React Router 7 with Vite

React Router is a standard library for routing in React applications that enables dynamic, client-side routing. This document explains how to integrate Flagship feature flag management with React Router 7 in a Vite-powered React application.

Project Overview

This project demonstrates how to integrate Flagship feature flagging system with a React Router 7 application. The integration allows you to:

  • Toggle features based on Flagship flags

  • Send analytics hits to track user behavior

  • Display different UI components based on feature flags

  • Route between different pages with flag-controlled behavior

Setup and Configuration

1. Flagship Provider Setup

The application uses a custom FsProvider component from FsProvider.tsx to initialize Flagship with your environment credentials:

// helpers/FsProvider.tsx
import FlagshipProvider, {
  LogLevel,
  type VisitorData,
} from "@flagship.io/react-sdk";
import { Loader } from "../components/Loader";

export function FsProvider({
  children,
  visitorData
}: {
  children: React.ReactNode;
  visitorData?: VisitorData;
}) {
  return (
    <FlagshipProvider
      envId={import.meta.env.VITE_ENV_ID} // Environment ID from Flagship
      apiKey={import.meta.env.VITE_API_KEY} // API Key from Flagship
      logLevel={LogLevel.DEBUG}
      visitorData={visitorData || null} // visitor data to pass
      loadingComponent={<Loader />} // Optional Loading component while flags are being fetched
    >
      {children}
    </FlagshipProvider>
  );
}

2. Application Structure

The main application structure in App.tsx sets up React Router and wraps everything in the Flagship provider:

// App.tsx
import { useState } from "react";
import { createBrowserRouter, RouterProvider } from "react-router";
import Home from "./routes/home";
import { FsProvider } from "./helpers/FsProvider";
import AnotherPage from "./routes/anotherPage";
import { Layout } from "./Layout";

const router = createBrowserRouter([
  {
    path: "/",
    Component: Layout,
    children: [
      {
        index: true,
        Component: Home,
      },
      {
        path: "another-page",
        Component: AnotherPage,
      },
    ],
  },
]);

function App() {

    // Initialize visitor data
  const [visitorData, setVisitorData] = useState({
    hasConsented: true,
  });

  return (
    <FsProvider
      visitorData={visitorData}
    >
      <RouterProvider router={router} />
    </FsProvider>
  );
}

3. Layout Component

The application uses a common layout with navigation in Layout.tsx:

// Layout.tsx
import { Outlet } from "react-router";
import Nav from "./components/Nav";

export function Layout() {
  return (
    <div className={"container"}>
      <div className="nav">
        <Nav />
      </div>
      <main className={"main"}>
        <Outlet />
      </main>
    </div>
  );
}

4. Navigation Component

The navigation component in Nav.tsx uses React Router's Link component:

// components/Nav.tsx
import { Link } from "react-router";

export default function Nav() {
  return (
    <>
      <Link to="/">Home</Link>
      <Link to="/another-page">Page - 2</Link>
    </>
  );
}

Using Flagship Flags

There are two main ways to access feature flags in your components:

Option 1: Use the useFsFlag Hook Directly

As shown in anotherPage.tsx:

// routes/anotherPage.tsx
import { useFsFlag } from "@flagship.io/react-sdk";

export default function AnotherPage() {
  // Get the flag `btnColor` using useFsFlag hook
  const flag = useFsFlag("btnColor");
  const flagValue = flag.getValue("#dc3545");

  return (
    <>
      <h1>This is another page</h1>
      <p>flag key: btnColor</p>
      <p>flag value: {flagValue}</p>
      <button style={{ background: flagValue }}>Click me</button>
    </>
  );
}

Option 2: Create Reusable Flag Components

For better reusability, create dedicated components like MyFlagComponent.tsx:

// components/MyFlagComponent.tsx
import { useFsFlag } from "@flagship.io/react-sdk";

export function MyFlagComponent() {
    // Replace 'my_flag_key' with the actual key of the flag you want to use
    const myFlag = useFsFlag("my_flag_key");
    return <p>flag value: {myFlag.getValue("default-value")}</p>
}

Then use this component in your routes like home.tsx:

// routes/home.tsx
import { MyFlagComponent } from "../components/MyFlagComponent";
import { MyButtonSendHit } from "../components/MyButtonSendHit";

export default function Home() {
  return (
    <>
      <h1>Example of Flagship implementation with React Router framework</h1>
      <p>flag key: my_flag_key</p>
      <MyFlagComponent />
      <MyButtonSendHit />
    </>
  );
}

Sending Analytics Hits

To track user actions, you can send analytics hits using the Flagship SDK as shown in MyButtonSendHit.tsx:

// components/MyButtonSendHit.tsx
import { useFlagship, HitType, EventCategory } from "@flagship.io/react-sdk";

export function MyButtonSendHit() {
  const fs = useFlagship();

  const onSendHitClick = () => {
    // This will send a hit to Flagship
    fs.sendHits({
      type: HitType.EVENT,
      category: EventCategory.ACTION_TRACKING,
      action: "click button",
    });
  };

  return (
    <button
      style={{ width: 100, height: 50 }}
      onClick={() => {
        onSendHitClick();
      }}
    >
      Send hits
    </button>
  );
}

Handling Loading States

The application includes a loading component in Loader.tsx that displays while Flagship flags are being fetched:

// components/Loader.tsx
export function Loader() {
    return (
        <div className='loader'>
            <div className="lds-ring"><div></div><div></div><div></div><div></div></div>
        </div>
    )
}

Environment Configuration

For Flagship to work properly, you need to set up the following environment variables in a .env.local file:

VITE_ENV_ID=your-flagship-environment-id
VITE_API_KEY=your-flagship-api-key

Running the Application

To run the application:

# Install dependencies
yarn install

# Start development server
yarn dev

# Build for production
yarn build

# Preview production build
yarn preview

Additional Considerations

  1. Visitor Data: You can customize the visitor data passed to Flagship in the FsProvider component.

  2. Default Values: Always provide default values for flags in case they can't be retrieved from Flagship.

  3. Error Handling: Consider adding error boundaries around components that depend on feature flags.

  4. Performance: Be mindful of how many flag lookups you're performing in frequently re-rendered components.

For more information about Flagship, refer to the official documentation.

Last updated

Was this helpful?