Skip to main content

Statsig in React Native

Installation

Statsig uses a multi-package strategy, so you will need to install both the Statsig client and the React Native specific bindings.

npm install @statsig/react-native-bindings

Peer Dependencies

The @statsig/react-native-bindings package has peer dependencies which may also need to be installed if they are not already in your project.

npm install react-native-device-info @react-native-async-storage/async-storage

React Native + React Specific Setup

The setup for a ReactNative environment is very similar to a plain React environment. The only difference is that you need to use the ReactNative specific StatsigProviderRN. This automatically switches out the storage layer used by the SDK, utilizing AsyncStorage instead of LocalStorage (which isn't available in RN environments).

import {
StatsigProviderRN,
useFeatureGate,
} from '@statsig/react-native-bindings';

function Content() {
const gate = useFeatureGate('a_gate');

// Reason: Network or NetworkNotModified
return (
<View>
<Text>Value: {gate.value ? "Pass" : "Fail"}</Text>
<Text>Reason: {gate.details.reason}</Text>
</View>
);
}

function App() {
return (
<StatsigProviderRN
sdkKey={YOUR_CLIENT_KEY}
user={{ userID: "a-user" }}
loadingComponent={<Text>Loading...</Text>}>
<Content />
</StatsigProviderRN>
);
}

The Basics

You can get an instance of the StatsigClient to check gates, experiments, dynamic configs, layers, and log events.

import { useStatsigClient } from "@statsig/react-native-bindings";

const { client } = useStatsigClient();

See the methods you can call on the client below.

Checking a Feature Flag/Gate

You can evaluate a gate by getting the client with the useStatsigClient hook, and then calling checkGate

const { client } = useStatsigClient();
return (
<div>Gate is {client.checkGate('check_user') ? 'passing' : 'failing'}.</div>
);

Getting a DynamicConfig

You can get a DynamicConfig value by getting the client with the useStatsigClient hook, and then calling getConfig

const { client } = useStatsigClient();
const config = client.getConfig('app_properties');

return (
<div>{config.get('title', 'Default Title')}</div>
);

Logging an Event

You can get the client with the useStatsigClient hook, and then call logEvent

const { client } = useStatsigClient();
return <button onClick={() => client.logEvent("button_click")}>Click Me</button>

Getting an Experiment

You can access the experiment variant and parameters for the user by getting the client with the useStatsigClient hook, and then calling getExperiment.

const { client } = useStatsigClient();
const experiment = client.getExperiment('headline_test');

return (
<div>Headline Parameter: {experiment.get('headline', 'Default')}.</div>
);

Getting a Layer

You can access layers and layer parameters for the user by getting the client with the useStatsigClient hook, and then calling getLayer.

const { client } = useStatsigClient();
const layer = client.getLayer('homepage_layer');

return (
<div>Headline Parameter: {layer.get('hero_text', 'Welcome')}.</div>
);

Loading State

Dependent on your setup, you may want to wait for the latest values before checking a gate or experiment. If you are using the StatsigProviderRN, you can pass in a loadingComponent prop to display a loading state while the SDK is initializing. If you are using the useClientAsyncInitRN hook, you can check the isLoading prop to determine if the SDK is still loading.

export function App() {
const loadingComponent = <div>Loading...</div>;

return (
<StatsigProviderRN
...
loadingComponent={loadingComponent} // <- Pass in the loading component
>
<YourComponent />
</StatsigProviderRN>
);
}

Advanced

StatsigClient Outside the Component Tree

In some scenarios, you may need to use the StatsigClient when you are not in the React component tree. Things like background tasks or handling notifications. For these, you can use the RN-specific StatsigClientRN.

import { StatsigClientRN } from '@statsig/react-native-bindings';

const myClient = new StatsigClientRN(
YOUR_CLIENT_KEY,
{ userID: "a-user" }
);

await myClient.initializeAsync();

if (myClient.checkGate("my_gate")) {
// do something cool
}

If you would like to access the StatsigClient instance that was created by the StatsigProvider outside of the component tree, you can use the StatsigClientRN.instance() method. This will return the first StatsigClient instance that was created. If you have multiple instances, you can pass in the SDK key to get a specific instance.

// Inside the component tree
function App() {
return <StatsigProviderRN sdkKey={YOUR_CLIENT_KEY} user={{ userID: "a-user" }}>
<Text>...</Text>
</StatsigProviderRN>
}

// Outside the component tree
const client = StatsigClientRN.instance(); // get the first created instance

const client = StatsigClientRN.instance(YOUR_CLIENT_KEY); // get a specific instance by SDK key

Synchronous Storage with MMKV

Due to the lack of LocalStorage in ReactNative environments, by default the SDK will prefetch all Statsig cache entries during initialization.

If you are utilizing MMKV in your project, and would prefer to use that instead of the default (AsyncStorage). You can provide you own StorageProvider via StatsigOptions.

Something like:

import { MMKV } from "react-native-mmkv";
import { StorageProvider } from "@statsig/client-core";
import { StatsigProviderRN } from '@statsig/react-native-bindings';

function App() {
const [storageProvider] = useState<StorageProvider>(() => {
const mmkv = new MMKV();

return {
isReady: () => true,
isReadyResolver: () => null,
getProviderName: () => "MMKV",
getAllKeys: () => mmkv.getAllKeys(),
getItem: (key: string) => mmkv.getString(key) ?? null,
setItem: (key: string, value: string) => mmkv.set(key, value),
removeItem: (key: string) => mmkv.delete(key),
};
});

return (
<StatsigProviderExpo
sdkKey={YOUR_CLIENT_KEY}
user={{ userID: "a-user" }}
options={{
storageProvider, // <- Passed into StatsigOptions
}}
>
<Text>...</Text>
</StatsigProviderExpo>
);
}