React Web SDK 3.x to 4.0 migration guide

Overview

This topic explains the changes in the React Web SDK 4.0 release and how to adapt code that uses a 3.x version of the React Web SDK to use version 4 or later.

After you complete the migration, your application will be running the React Web SDK version 4.0.

To learn more, read the React Web SDK reference and React Server Component support.

Before you migrate to version 4, update to the latest 3.x version. Some of the changes that are mandatory in 4 were originally added in a 3.x version and made optional.

Review the JavaScript SDK 3.x to 4.0 migration guide too

The React Web SDK is based on @launchdarkly/js-client-sdk which is our JavaScript SDK at version 4.0.0 and higher.

To learn about the differences between that version and the older versions of the JavaScript SDK, read the JavaScript SDK 3.x to 4.0 migration guide. Those changes are also relevant to the React SDK.

Prerequisites

To complete this migration, you must have the following prerequisites:

  • A LaunchDarkly account.
  • React version 18.0.0 or higher. We recommend using React 19 if possible.
  • React Web SDK version 3.x installed.

React Server Components are stable in React 19, but are only stable in some frameworks. You must be on React 19 to leverage the server submodule. An earlier version of React may work if you are only using the @launchdarkly/react-sdk package, but it is not officially supported.

Understanding what changed in version 4.0

Introducing support for React Server Components

This update includes support for React Server Components. That functionality is included in the React Web SDK. To learn more, read React Server Component support.

There are several significant changes to version 4.0 of the React Web SDK.

Named contexts

Version 4.0 supports custom React contexts with the reactContext option on createLDReactProvider and through an optional argument on every hook.

Here’s an example:

1import { withLDProvider, withLDConsumer } from 'launchdarkly-react-client-sdk';
2const MyContext = React.createContext(null);
3
4export default withLDProvider({
5 clientSideID: 'your-id',
6 reactContext: MyContext,
7})(App);
8
9const MyComponent = withLDConsumer({ reactContext: MyContext })(({ flags, ldClient }) => (
10 <div>{flags.myFlag ? 'on' : 'off'}</div>
11));

useInitializationStatus replaces useLDClientError

The old useLDClientError only returned an error when the client failed to initialize. The new useInitializationStatus() provides both the full initialization state and the error.

1import { useLDClientError } from 'launchdarkly-react-client-sdk';
2const error = useLDClientError(); // Error | undefined

useInitializationStatus tells you the full state of initialization, not only if there was an error. Use status to gate rendering and error for error reporting.

useInitializationStatus replaces asyncWithLDProvider

The old function blocked rendering until the client initialized. In version 4, you can use useInitializationStatus to conditionally render loading or error states.

1// `asyncWithLDProvider` blocked until flags were ready
2const LDProvider = await asyncWithLDProvider({ clientSideID: 'your-client-side-id' });
3root.render(<LDProvider><App /></LDProvider>);

Removed higher-order components: withLDProvider and asyncWithLDProvider

We’ve removed our higher-order components as the React ecosystem now heavily favors the hooks pattern. We strongly recommend migrating to use our createLDReactProvider for client instantiation.

However, if you prefer to continue using HOCs, you can create a HOC using our alternative createClient.

React Web SDK v4.0
1import { createClient } from '@launchdarkly/react-sdk';
2
3const client = createClient('your-client-side-id', { kind: 'user', key: 'example-user-key' });
4
5export default (WrappedComponent) => {
6 return (props) => {
7 return <WrappedComponent {...props} ldClient={client} />
8 }
9}

Remember, createClient does not automatically call the start() method that kicks off the SDK client initialization.

Changed deferred initialization behavior

deferInitialization has changed option location, its default value, how it behaves when set to true, and how it starts manually.

Something went wrong!

If you use the low-level API, createLDReactProviderWithClient always behaves as if deferInitialization: true. It never calls start() automatically.

Bootstrap is now a top-level option

In v3.x, bootstrap data was nested inside options. In v4.0, bootstrap is a top-level option on createLDReactProvider.

The bootstrap data format is unchanged. You can pass either a plain key-value object, such as { 'example-flag-key': true }, or the output of allFlagsState().toJSON(), which includes $flagsState and $valid metadata.

1// Higher-order component
2withLDProvider({
3 clientSideID: 'your-client-side-id',
4 options: { bootstrap: myData },
5})(App);
6
7// Async higher-order component
8const LDProvider = await asyncWithLDProvider({
9 clientSideID: 'your-client-side-id',
10 options: { bootstrap: myData },
11});

You can also pass bootstrap data through startOptions.bootstrap. The top-level bootstrap option is merged into startOptions.bootstrap when the client starts. If you provide both, the top-level value takes precedence.

React Web SDK v4.0
1import { createLDReactProvider } from '@launchdarkly/react-sdk';
2
3const LDProvider = createLDReactProvider(
4 'your-client-side-id',
5 { kind: 'user', key: 'user-key' },
6 {
7 startOptions: {
8 bootstrap: myData,
9 },
10 },
11);

Deprecations

useFlags is available, but deprecated. We strongly recommend using typed variation hooks for flag evaluations instead.

If you must, you can call allFlags from the LDClient. Here’s how:

React Web SDK v4.0
1import { useLDClient } from '@launchdarkly/react-sdk';
2
3const ldClient = useLDClient();
4const flags = ldClient.allFlags();

Removed APIs

The following APIs have been removed:

  • useLDClientError(), replaced with useInitializationStatus().error.
  • withLDProvider(), replaced with createLDReactProvider().
  • asyncWithLDProvider(), replaced with createLDReactProvider().
  • withLDConsumer(), replaced with useLDClient(), and typed variation hooks such as useBoolVariation(), useStringVariation(), useNumberVariation(), useJsonVariation().
  • LDProvider component, replaced with createLDReactProvider().
  • reactSdkContextFactory(), replaced with initLDReactContext(). To learn more, read Named contexts, above.
  • camelCaseKeys() utility function. Camel-case key conversion is no longer exposed as a standalone helper. The typed variation hooks always use the original flag key. The useFlags hook still applies camel-casing internally and can be opted out of with ldOptions.useCamelCaseFlagKeys: false.

Updating your dependencies

@launchdarkly/js-client-sdk is bundled as a transitive dependency of @launchdarkly/react-sdk. You do not need to install or update it manually.