@featureflare/react
v0.0.42
Published
React hooks and provider for FeatureFlare feature flags.
Readme
@featureflare/react
React hooks and provider for FeatureFlare feature flags.
Installation
npm install @featureflare/react
# or
pnpm add @featureflare/react
# or
yarn add @featureflare/reactUsage
Minimal Setup
import { FeatureFlareProvider, resolveFeatureFlareBrowserConfig, useFlags } from '@featureflare/react';
function FlagsBootstrap() {
useFlags({
user: { id: 'user-123', email: '[email protected]' },
defaultValue: false,
refreshIntervalMs: 10000,
pauseWhenHidden: true,
});
return null;
}
export function App() {
const config = resolveFeatureFlareBrowserConfig();
if (!config.sdkKey) {
return <div>Feature flags disabled</div>;
}
return (
<FeatureFlareProvider
config={{
...config,
bootstrap: {
flags: { 'new-nav': true }
}
}}
initialUser={{ id: 'user-123', key: 'user-123' }}
>
<FlagsBootstrap />
{/* app */}
</FeatureFlareProvider>
);
}Read One Flag
import { useFlag } from '@featureflare/react';
export function NewNav() {
const { value, loading, error } = useFlag('new-nav', false);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return value ? <div>New nav ON</div> : <div>New nav OFF</div>;
}SSR/HTML Bootstrap (anti-flicker working flow)
Server-side (example in Next.js getServerSideProps):
import { FeatureFlareClient } from '@featureflare/sdk-js';
export async function getServerSideProps() {
const user = { id: 'user-123', key: 'user-123' };
const sdk = new FeatureFlareClient({
apiBaseUrl: process.env.FEATUREFLARE_API_BASE_URL,
sdkKey: process.env.FEATUREFLARE_SERVER_SDK_KEY
});
const nav = await sdk.bool('new-nav', user, false);
return {
props: {
user,
ffBootstrap: {
flags: { 'new-nav': nav }
}
}
};
}Client-side provider wiring:
import { FeatureFlareProvider, resolveFeatureFlareBrowserConfig } from '@featureflare/react';
export default function Page({ user, ffBootstrap }) {
const config = resolveFeatureFlareBrowserConfig();
return (
<FeatureFlareProvider
config={{
...config,
bootstrap: ffBootstrap
}}
initialUser={user}
>
{/* First render uses bootstrap synchronously; no loading flicker for these flags */}
<App />
</FeatureFlareProvider>
);
}For non-SSR apps, inject a bootstrap JSON payload into HTML before app startup and pass it to config.bootstrap the same way.
API
FeatureFlareProvider
Props:
config: FeatureFlareReactConfiginitialUser: FeatureFlareUserPayloaduser?: FeatureFlareUserPayload(controlled mode)onUserChange?: (user: FeatureFlareUserPayload) => void(required in controlled mode)children: React.ReactNode
resolveFeatureFlareBrowserConfig(input?)
Builds provider config from common NEXT_PUBLIC_FEATUREFLARE_* vars.
Returns:
apiBaseUrl?: stringenvKey: 'development' | 'staging' | 'production'sdkKey?: string
useFeatureFlareUser()
Returns:
[user, setUser]
useFlags(...)
Signatures:
useFlags(keys: string[], defaultValue?: boolean)→{ values, loading, errors }useFlags(input?: { user?: FeatureFlareUserPayload; defaultValue?: boolean; refreshIntervalMs?: number; hiddenRefreshIntervalMs?: number; pauseWhenHidden?: boolean; enabled?: boolean })useFlags(defaultValue?: boolean, options?: { refreshIntervalMs?: number; hiddenRefreshIntervalMs?: number; pauseWhenHidden?: boolean; enabled?: boolean })
useBoolFlags(...)
Signatures:
useBoolFlags(keys: string[], defaultValue?: boolean)→{ values, loading, errors }useBoolFlags(defaultValue?: boolean, options?: { refreshIntervalMs?: number; hiddenRefreshIntervalMs?: number; pauseWhenHidden?: boolean; enabled?: boolean })→{ values, loading, errors }(all flags)
Returns:
flags: Array<{ key: string; value: boolean }>loading: booleanerror: string | null
useFlag(key, defaultValue?)
Selector-based single-flag subscription. Components only re-render when that flag changes.
useFlagDiagnostics(key)
Returns per-flag runtime diagnostics (source, stale state, cache timestamps, latency).
Behavior:
- Immediate fetch on mount/user change.
- Shared polling via provider context (multiple consumers do not duplicate requests).
- Optional polling controls with hidden-tab awareness.
- If
useris provided in input form, hook syncs provider user automatically.
Notes
- Use client SDK keys in browser apps.
- If
config.sdkKeyis missing, skip initializing the provider.
Security: Client-side flags are not authorization
Client keys can be extracted from your frontend bundle. Never gate truly sensitive operations solely with client-evaluated flags—enforce authorization on your backend.
config.bootstrap?: { flags, killSwitches }for SSR/HTML bootstrap to avoid first-render flickerconfig.timeoutMs | maxRetries | backoffMs | jitter | cacheTtlMs | staleTtlMs | realtimeare forwarded to the SDK client
