Advanced Usage
Advanced features and patterns for the React Native SDK.
Extensibility Hooks
Integrate with analytics, monitoring, or implement custom behaviors using hooks.
Creating a Hook
import { Hook } from '@ops-ai/toggly-hooks-types';
const analyticsHook: Hook = {
getMetadata: () => ({
name: 'Analytics',
version: '1.0.0',
}),
beforeEvaluation: async (data) => {
// Called before feature evaluation
console.log('Evaluating:', data.featureKey);
},
afterEvaluation: async (data) => {
// Called after evaluation
analytics.track('Feature Evaluated', {
feature: data.featureKey,
enabled: data.result,
userId: data.userId,
});
},
beforeIdentify: async (data) => {
// Called before identity change
console.log('Changing identity from:', data.previousUserId);
},
afterIdentify: async (data) => {
// Called after identity change
analytics.identify(data.userId);
},
afterRefresh: async () => {
// Called after flags refresh
console.log('Flags refreshed');
},
};
Registering Hooks
At initialization:
<TogglyProvider
appKey="your-app-key"
environment="production"
hooks={[analyticsHook, loggingHook]}
>
<App />
</TogglyProvider>
At runtime:
function App() {
const { toggly } = useToggly();
useEffect(() => {
toggly.addHook(analyticsHook);
return () => {
toggly.removeHook(analyticsHook);
};
}, [toggly]);
return <Content />;
}
Hook Execution Order
- before hooks: Execute in FIFO order (first registered, first executed)
- after hooks: Execute in LIFO order (last registered, first executed)
This creates a "wrap" pattern similar to middleware.
Common Hook Use Cases
Firebase Analytics:
const firebaseHook: Hook = {
getMetadata: () => ({ name: 'Firebase', version: '1.0.0' }),
afterEvaluation: async (data) => {
await analytics().logEvent('feature_flag_evaluated', {
feature_key: data.featureKey,
enabled: data.result,
});
},
};
Debug Logging:
const debugHook: Hook = {
getMetadata: () => ({ name: 'Debug', version: '1.0.0' }),
afterEvaluation: async (data) => {
if (__DEV__) {
console.log(`[Toggly] ${data.featureKey} = ${data.result}`);
}
},
};
Device-local post-filter gates
Gate bundles of flags behind device-local master switches (AsyncStorage, Settings,
debug menus) while worker rollouts stay on Toggly. Effective value is
remote AND local at read time — the cached remote map is never mutated.
See the full guide: Post-filter gates.
Register at provider init
import type { LocalGate } from '@ops-ai/react-native-toggly-core';
let apiRedesignEnabled = false;
const localGates: LocalGate[] = [{
id: 'apiRedesign',
flagKeys: ['ApiV2Checkout', 'ApiV2Profile'],
isEnabled: () => apiRedesignEnabled,
}];
<TogglyProvider
appKey="your-app-key"
environment="Production"
localGates={localGates}
>
<App />
</TogglyProvider>
Update at runtime
function SettingsScreen() {
const { toggly } = useTogglyContext();
const turnOff = () => {
apiRedesignEnabled = false;
toggly.setLocalGates([{
id: 'apiRedesign',
flagKeys: ['ApiV2Checkout', 'ApiV2Profile'],
isEnabled: () => apiRedesignEnabled,
}]);
// Instant — no network; hooks and <Feature> re-read effective flags
toggly.notifyLocalGatesChanged();
};
const turnOn = async () => {
apiRedesignEnabled = true;
await toggly.refresh(); // pick up remote rollouts for newly enabled gate
toggly.notifyLocalGatesChanged();
};
}
| API | Purpose |
|---|---|
localGates (provider / config) | Initial gate registry |
setLocalGates(gates) | Replace the registry at runtime |
notifyLocalGatesChanged() | Recompute effective flags locally; emit UI updates (no network) |
useFeatureFlag, useFeatureGate, and <Feature> subscribe to
effectiveFlagsChanged, so they re-render when you call
notifyLocalGatesChanged().
Post-filter gates are for UX and product gating on the device. Enforce security-sensitive behavior on your server as well.
Offline Support
The SDK handles offline scenarios gracefully.