ابرووا
شروع رایگان
☰ فهرست مستندات · React Native
به‌زودی. Abrova Flags به‌زودی فعال می‌شود. این صفحه توضیح می‌دهد چطور کار خواهد کرد؛ هنوز قابل استفاده نیست.
این صفحه هنوز ترجمه نشده — نسخه‌ی انگلیسی نمایش داده می‌شود. English

React Native SDK

Feature flags for React Native, evaluated by Abrova Flags for the current user and cached with AsyncStorage. Provider, hooks, typed getters and anonymous id. Public API key only.

React Native 0.2.0React Native 0.70+React 18+به‌روزرسانی: ۵ آبان ۱۴۰۵
Client-Safe

Uses the public API key only. No server secret needed

Evaluated by the Service

The app receives values for this user. Targeting rules never reach the device

React Hooks

useAbrovaFlags and one hook per flag type. Components re-render when values change

Typed Getters

getBoolean, getString, getNumber and getJson, each with a default

Offline Cache

The last values are stored with AsyncStorage and served at start and offline

Anonymous Id

Percentage rollouts also work before sign-in

Abrova Flags React Native SDK v0.2.0.

This page describes @abrova/flags-react-native 0.2.0. It is a breaking release: flags are evaluated by the service instead of on the device, and the getters changed. Coming from 0.1.x? See Upgrading from 0.1.x at the end of this page.

Requirements.

React 18 or higher. React Native 0.70 or higher.

Installation#

bash
# 1. .npmrc in your project root: @abrova packages come from Abrova Center
@abrova:registry=https://center.abrova.ir/api/packages/abrova/npm/
bash
# 2. Install
npm install @abrova/flags-react-native @react-native-async-storage/async-storage
cd ios && pod install

@react-native-async-storage/async-storage stores the anonymous id and the last values. Without it the SDK still works, but keeps them in memory only and logs a warning.

Provider and hooks#

Wrap your app in AbrovaFlagsProvider. It creates the client, initialises it and closes it when the provider unmounts. Use your public API key (ab_live_...).

tsx
import React from 'react';
import { AbrovaFlagsProvider } from '@abrova/flags-react-native';

export default function App() {
  return (
    <AbrovaFlagsProvider config={{ apiKey: 'ab_live_xxx', environment: 'production' }}>
      <Checkout />
    </AbrovaFlagsProvider>
  );
}

Read flags with the hooks. A component that uses a hook re-renders when the values change.

tsx
import { useAbrovaFlags, useStringFlag } from '@abrova/flags-react-native';

function Checkout() {
  const { isReady, isEnabled, getNumber } = useAbrovaFlags();
  const theme = useStringFlag('theme', 'light');

  if (!isReady) return <Loading />;

  return isEnabled('new-checkout')
    ? <NewCheckout theme={theme} maxItems={getNumber('max-items', 10)} />
    : <OldCheckout />;
}
HookReturns
useAbrovaFlags()client, isReady, anonymousId, userId, the getters, identify, setUserId, setAttributes, reset, resetAnonymousId and refresh
useFlagEnabled(key, defaultValue = false)true when the flag is served on for this user
useBooleanFlag(key, defaultValue)Value of a boolean flag
useStringFlag(key, defaultValue)Value of a string flag
useNumberFlag(key, defaultValue)Value of a number flag
useJsonFlag(key, defaultValue)Value of a json flag
useFlagDetail(key, defaultValue)value, enabled, variant, reason and version of one flag

The functions returned by useAbrovaFlags() are bound to the client, so you can destructure them. If you created the client yourself, pass it with client instead of config; the provider then leaves init() and close() to you.

Direct Usage#

You can use the client without React.

typescript
import { AbrovaFlags } from '@abrova/flags-react-native';

const flags = new AbrovaFlags({ apiKey: 'ab_live_xxx', environment: 'production' });
await flags.init();

if (flags.isEnabled('new-checkout')) {
  // Show the new checkout
}

const dark = flags.getBoolean('dark-mode', false);
const theme = flags.getString('theme', 'light');
const maxItems = flags.getNumber('max-items', 10);
const layout = flags.getJson('home-layout', { columns: 2 });

init() serves the values cached on the device right away and waits up to initTimeoutMs (5 seconds) for the first answer from the network. After init(), the client is also available as AbrovaFlags.instance.

Getters are synchronous and never throw. Each one takes the default to use when the flag is unknown, when no values are available yet, or when the flag has another type.

Never use the server secret in an app.

The constructor throws if apiKey is a server secret (ab_srv_...). The server secret belongs on your backend, with the Node.js or Next.js server SDK.

Details and reasons

typescript
const d = flags.getStringDetail('theme', 'light');
// { value, enabled, variant, reason, version }

getBooleanDetail, getStringDetail, getNumberDetail and getJsonDetail check the flag type. getDetail(key, defaultValue) returns the stored value without a type check, and getAll() returns every value held.

ReasonMeaning
ONThe flag is on and has no variants. The value is true
VARIANTThe flag is on and a variant was served
DISABLEDThe flag is off in this environment. The flag off value is served
NOT_TARGETEDThe targeting rules did not match this user. The off value is served
OUTSIDE_ROLLOUTThe user is outside the rollout percentage. The off value is served
PREREQUISITE_FAILEDA flag this one depends on did not give the required result. The off value is served
NO_BUCKETING_IDA rollout or split needed a user id or anonymous id and none was sent
ERRORThe flag could not be evaluated. The off value is served
FLAG_NOT_FOUNDNo such flag. Your default is returned
NOT_READYNo cached or fetched values yet. Your default is returned
TYPE_MISMATCHFor example getString on a boolean flag. Your default is returned

isEnabled is true only for ON and VARIANT.

Identify the user#

Tell the SDK who the user is and what you know about them. Targeting rules and percentage rollouts are evaluated against this context.

typescript
// After sign-in
await flags.identify('user-123', { plan: 'pro', country: 'IR', beta: true });

// Replace all attributes
await flags.setAttributes({ plan: 'business' });

// Signed out, attributes stay
await flags.setUserId(null);

// Sign-out: clears the user id, the attributes and the cached values
await flags.reset();

In a component, call identify in an effect so it runs only when the user changes. Use client from the hook in the dependency list: it stays the same between renders, while the functions returned by the hook are created again when values change.

tsx
import { useEffect } from 'react';
import { useAbrovaFlags } from '@abrova/flags-react-native';

function Session({ userId, plan }: { userId: string | null; plan: string }) {
  const { client } = useAbrovaFlags();

  useEffect(() => {
    client.identify(userId, { plan }); // null means signed out
  }, [client, userId, plan]);

  return null;
}
  • Each change fetches new values after a short pause (250 ms), so several calls in a row send one request.
  • setAttributes and the attributes of identify replace the whole set. They do not merge.
  • When the user id changes, the previous user's values are dropped at once. Until the new values arrive, getters return your defaults (reason NOT_READY).
  • Attributes are strings, numbers, booleans, null, or arrays of those. No nested objects. At most 100 attributes; a string holds at most 1,024 characters.

If you already know the user at start, pass userId and attributes in the config. The SDK then serves that user's cached values immediately and sends one request instead of two.

Anonymous id

Every install gets a random anonymous id (a UUID). It is stored on the device and sent with every request, so a 10% rollout reaches about 10% of signed-out installs too. When a user id is set, rollouts use the user id instead.

The anonymous id survives reset(). resetAnonymousId() replaces it. Read it with flags.anonymousId.

Updates and refresh#

typescript
// New values arrived
const unsubscribe = flags.subscribe(() => console.log('flags changed'));

// A request failed
const off = flags.onError((e) => console.log(e.statusCode, e.code, e.message));

// Fetch now
await flags.refresh();

The SDK fetches values:

  • on init(),
  • after identify, setUserId, setAttributes, reset and resetAnonymousId,
  • when the app returns to the foreground and the last fetch is older than 15 minutes,
  • on refresh(),
  • on a timer, only if you set refreshIntervalSeconds.
Each fetch counts as one evaluation.

Every request for values is counted as one flag evaluation, whatever the number of flags it returns (100,000 evaluations are free every month; the price above that is set at launch). This is why polling is off by default. identify, setUserId and setAttributes send a request every time you call them, also when nothing changed, so call them in an effect with dependencies, not on every render.

Offline and errors#

The last values are stored with AsyncStorage and served at the next start, before the network answers. A failed request never clears them.

  • Offline or server error: the last values keep being served. The SDK retries with a growing delay (up to 5 minutes).
  • Rate limited (429): the SDK waits the time the service asks for, then retries.
  • 401, 403 or 404 (wrong key, Flags not enabled for the project, unknown environment): automatic fetches stop until you call refresh() or restart the app. Check flags.lastError.
  • Before the first values: flags.isReady is false and getters return your defaults. await flags.whenReady() resolves when values are available.

flags.close() stops timers and network work.

Configuration Options#

OptionTypeDefaultDescription
apiKeystringrequiredYour public API key (ab_live_xxx)
environmentstringnoneEnvironment key (production, staging, development or your own). Leave out to use the Default values
userIdstring | nullnullSigned-in user id at start
attributesobject{}Targeting attributes at start
flagKeysstring[]all flagsOnly fetch these flags
refreshIntervalSecondsnumber0Polling while the app is in the foreground. 0 is off; otherwise at least 60
initTimeoutMsnumber5000How long init() waits for the first answer
observeAppStatebooleantrueRefresh when the app returns to the foreground
storageFlagsStorageAsyncStorageWhere the anonymous id and the last values are kept
debugbooleanfalseVerbose logs. Errors are always logged

Testing#

Pass an in-memory store, your own fetch and observeAppState: false:

typescript
import { AbrovaFlags, MemoryFlagsStorage } from '@abrova/flags-react-native';

const flags = new AbrovaFlags({
  apiKey: 'ab_live_xxx',
  storage: new MemoryFlagsStorage(),
  fetch: mockFetch,
  observeAppState: false,
});

Upgrading from 0.1.x#

0.2.0 is a new API, and 0.1.x clients stop receiving flags. Update the package and change these calls:

0.1.x0.2.0
getValue('k', x)getBoolean / getString / getNumber / getJson('k', x)
evaluate('k')getDetail('k', x), which adds reason and version
setUserId(id) + setUserAttributes(map), mergedidentify(id, attributes), setUserId, setAttributes. Attributes are replaced
getAll() returned flag configurations with rulesgetAll() returns this user's values only
init(callback)init(), plus subscribe() and onError()
isLoading from the hookisReady
enableOfflineCache, dispose()Always cached; close()
@react-native-community/netinfo peer dependencyNot needed. You can remove it if nothing else uses it

Rollouts use a new bucketing method, so users are assigned to rollouts and variants again once.

Best Practices#

Use the Provider

Wrap your app with AbrovaFlagsProvider so every component reads the same client

Identify in an effect

Call identify when the user or the attributes change, not on every render

Always give a sensible default

The default is what your users see before the first values and when a flag is removed

Reset on sign-out

Call reset() so the next user never sees the previous user's values

Leave polling off

Values refresh on start, on context changes and on app resume. Turn polling on only if you need faster updates

این صفحه مفید بود؟
گزارش مشکل