Hooks
The React Native SDK provides several React hooks for evaluating feature flags.
useFeatureFlag, useFeatureGate, and the context from useToggly re-evaluate
when remote flags refresh or when device-local post-filter gates change via
notifyLocalGatesChanged(). See Post-filter gates
and Advanced → Device-local post-filter gates.
useFeatureFlag
Check a single feature flag status.
import { useFeatureFlag } from '@ops-ai/react-native-toggly';
function MyComponent() {
const { isEnabled, isLoading, error } = useFeatureFlag('feature-key');
if (isLoading) return <Loading />;
if (error) return <Error message={error.message} />;
return isEnabled ? <NewFeature /> : <OldFeature />;
}
Return Value
| Property | Type | Description |
|---|---|---|
isEnabled | boolean | Whether the feature is enabled |
isLoading | boolean | Whether the SDK is still loading |
error | Error | null | Any error that occurred |
Options
const { isEnabled } = useFeatureFlag('feature-key', {
defaultValue: false, // Value to use while loading
});
useFeatureGate
Check multiple feature flags with all or any requirement.
import { useFeatureGate } from '@ops-ai/react-native-toggly';
function MyComponent() {
// All features must be enabled
const { isEnabled: allEnabled } = useFeatureGate(
['feature1', 'feature2'],
{ requirement: 'all' }
);
// At least one feature must be enabled
const { isEnabled: anyEnabled } = useFeatureGate(
['feature1', 'feature2'],
{ requirement: 'any' }
);
// Negate the result (show when features are OFF)
const { isEnabled: noneEnabled } = useFeatureGate(
['feature1', 'feature2'],
{ requirement: 'all', negate: true }
);
}
Options
| Option | Type | Default | Description |
|---|---|---|---|
requirement | 'all' | 'any' | 'all' | Whether all or any features must be enabled |
negate | boolean | false | Inverts the result |
defaultValue | boolean | false | Value while loading |
useToggly
Access the full Toggly service for advanced operations.
import { useToggly } from '@ops-ai/react-native-toggly';
function MyComponent() {
const {
toggly, // TogglyService instance
isReady, // SDK is initialized
isLoading, // Currently loading
error, // Initialization error
isFeatureOn, // Function to check feature
setIdentity, // Set user identity
refresh, // Manually refresh flags
getVariant, // Assigned variant { name, configurationValue } | null
getVariantValue, // Assigned variant's configurationValue, or null
recordUsage, // Explicit feature use
recordView, // Explicit feature view
incrementCounter, // App-level counter
setGauge, // App-level latest value
flushTelemetry, // Await current best-effort drain
} = useToggly();
const handleLogin = async (userId: string) => {
await setIdentity(userId);
};
const handleLogout = async () => {
await setIdentity(null);
};
const handleRefresh = async () => {
await refresh();
};
// Imperative feature check
const isPremium = isFeatureOn('premium-features');
}
Return Value
| Property | Type | Description |
|---|---|---|
toggly | TogglyService | The underlying Toggly service instance |
isReady | boolean | Whether the SDK is fully initialized |
isLoading | boolean | Whether the SDK is currently loading |
error | Error | null | Any initialization error |
isFeatureOn | (key: string) => boolean | Check if a feature is enabled |
setIdentity | (id: string | null) => Promise<void> | Set or clear user identity |
refresh | () => Promise<void> | Manually refresh feature flags |
getVariant | (key: string) => { name: string; configurationValue?: unknown } | null | Assigned variant for a feature (requires enableVariants); null when disabled, off, or unassigned |
getVariantValue | (key: string) => unknown | null | Shortcut for getVariant(key)?.configurationValue ?? null |
recordUsage / recordView | (key: string, variant?: string) => void | Count-only explicit events without evaluating the flag |
use | (key, fn, variant?) => Promise<T> | Usage scope: attempt, duration, and errors (concept) |
incrementCounter | (name: string, delta?: number) => void | Add a nonnegative integer delta; default 1 |
setGauge | (name: string, value: number) => void | Keep the latest finite nonnegative value |
flushTelemetry | () => Promise<void> | Drain current queued work on a best-effort basis |
useVariant
Read the assigned variant for a feature. Requires enableVariants: true on
TogglyProvider (or the underlying TogglyService config), which switches the
SDK to fetch /evaluated-variants-signed instead of /evaluated-signed.
Re-renders after feature definitions refresh or device-local gates change,
the same way useFeatureFlag does.
import { TogglyProvider, useVariant } from '@ops-ai/react-native-toggly';
function App() {
return (
<TogglyProvider appKey="your-app-key" environment="Production" enableVariants>
<PricingScreen />
</TogglyProvider>
);
}
function PricingScreen() {
const variant = useVariant('pricing-test');
if (variant?.name === 'treatment') {
return <NewPricing config={variant.configurationValue} />;
}
return <ControlPricing />;
}
useVariant returns null when enableVariants is off, the feature is
disabled, or no variant data has loaded yet — treat that the same as the
control/default experience.
Return Value
| Type | Description |
|---|---|
{ name: string; configurationValue?: unknown } | null | The assigned variant name and its configuration payload, or null |
Examples
Conditional Rendering
function CheckoutButton() {
const { isEnabled: useNewCheckout, isLoading } = useFeatureFlag('new-checkout');
if (isLoading) {
return <ActivityIndicator />;
}
return useNewCheckout ? (
<NewCheckoutButton onPress={handleNewCheckout} />
) : (
<ClassicCheckoutButton onPress={handleClassicCheckout} />
);
}
Combined Feature Gates
function PremiumContent() {
const { isEnabled: hasPremiumAccess } = useFeatureGate(
['premium-subscription', 'beta-tester'],
{ requirement: 'any' } // User has premium OR is beta tester
);
if (!hasPremiumAccess) {
return <UpgradePrompt />;
}
return <PremiumContentView />;
}
User Login/Logout
function AuthButtons() {
const { setIdentity, refresh } = useToggly();
const [user, setUser] = useState(null);
const handleLogin = async (credentials) => {
const userData = await loginAPI(credentials);
setUser(userData);
// Set identity for targeted feature rollouts
await setIdentity(userData.id);
};
const handleLogout = async () => {
await logoutAPI();
setUser(null);
// Clear identity
await setIdentity(null);
};
return (
<View>
{user ? (
<Button title="Logout" onPress={handleLogout} />
) : (
<Button title="Login" onPress={() => handleLogin(credentials)} />
)}
</View>
);
}
Manual Refresh
function SettingsScreen() {
const { refresh } = useToggly();
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
setRefreshing(true);
try {
await refresh();
} finally {
setRefreshing(false);
}
};
return (
<ScrollView
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
}
>
{/* Content */}
</ScrollView>
);
}
Entity context
Pass the entity into useFeatureFlag / useToggly().isFeatureOn per call. Do not put entity attributes on setIdentity. See Entity & page context.
const { enabled } = useFeatureFlag('OrderBadge', { context: order, contextKind: 'Order' })
Clients register mappers locally only. Missing context fails closed.
Best Practices
- Use
useFeatureFlagfor single flags - It's optimized for single feature checks - Use
useFeatureGatefor multiple flags - When you need AND/OR logic - Use
useTogglyfor advanced operations - Identity management, manual refresh - Handle loading states - Show appropriate UI while flags are loading
- Provide defaults - Use
featureDefaultsfor offline scenarios