# React

React apps use [`@flagbearer/web`](/sdks/web) with two small hooks. Read the
[Web SDK](/sdks/web) page for install, keys, users and defaults.

## One client, outside render

Create the client once, in its own module, not inside a component. Then read
flags with React's external-store hook:

```tsx
// src/flags.ts
import { useEffect, useSyncExternalStore } from "react";

import { init, type FlagKey } from "@flagbearer/web";

export const flags = init({ clientKey: "fbc_..." });

// FlagKey checks keys against the file from `generate types`, described on the
// Web SDK page.
export function useFlag(key: FlagKey, defaultValue: boolean) {
  const enabled = useSyncExternalStore(
    flags.subscribe,
    () => flags.getSnapshot()[key] ?? defaultValue,
    () => defaultValue,
  );

  useEffect(() => {
    flags.isEnabled(key, defaultValue);
  }, [key, defaultValue, enabled]);

  return enabled;
}

// False until the current user's flags have loaded.
export function useFlagsLoaded() {
  return useSyncExternalStore(
    flags.subscribe,
    () => flags.getStatus() !== "loading",
    () => false,
  );
}
```

## Users

When the signed-in user is known or changes, call `identify`, for example in the
component that loads the session:

```tsx
useEffect(() => {
  if (user) flags.identify({ key: user.id, email: user.email });
}, [user?.id]);
```

The email is optional. Include it to turn flags on for testers by email.

## Checking a flag

```tsx
const newCheckout = useFlag("new-checkout", false);
return newCheckout ? <NewCheckout /> : <Checkout />;
```

- **Defaults.** Pass the value the app should use before flags load.
- **No flash.** Use `useFlagsLoaded` to hold back UI that mustn't switch between
  the default and the real value:

  ```tsx
  const loaded = useFlagsLoaded();
  const newCheckout = useFlag("new-checkout", false);
  if (!loaded) return <Spinner />;
  return newCheckout ? <NewCheckout /> : <Checkout />;
  ```

## Server rendering and hydration

During server rendering and hydration, `useFlag` returns the default and
`useFlagsLoaded` returns `false`, so there are no hydration mismatches. The real
values take over once the client's flags load. Importing the flags module
during server rendering is safe.
