Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 'use client' import { useMemo } from 'react' import { useQuery } from '@tanstack/react-query' import { featureFlagKeys } from '@/lib/queryKeys' export interface FlagValue { enabled: boolean config: unknown } export type FlagsResponse = { flags: Record<string, FlagValue> } const EMPTY_FLAGS: Record<string, FlagValue> = {} async function fetchFlags(): Promise<FlagsResponse> { const res = await fetch('/api/feature-flags') if (!res.ok) throw new Error('Failed to fetch feature flags') return res.json() } /** * Hook to get all feature flags (bulk fetch). * Uses React Query with 60s stale time. */ export function useFeatureFlags() { const { data, isLoading } = useQuery({ queryKey: featureFlagKeys.all, queryFn: fetchFlags, staleTime: 60_000, }) return { flags: data?.flags ?? EMPTY_FLAGS, isLoading, } } /** * Hook to get a single feature flag by key. * * Performance: shares the bulk flags query (single HTTP request for all flags). * Uses React Query `select` to extract one flag, and `useMemo` on the return * value so consumers only re-render when `enabled` or `config` actually change. */ export function useFeatureFlag(key: string) { const { data, isLoading } = useQuery({ queryKey: featureFlagKeys.all, queryFn: fetchFlags, staleTime: 60_000, select: (data) => data.flags[key] ?? null, // React Query uses referential equality on select output by default. // structuralSharing deep-compares the selected value so a refetch that // returns identical data won't produce a new reference. structuralSharing: true, }) const enabled = data?.enabled ?? false const config = data?.config ?? null // Stable reference — only changes when the primitive `enabled` or // the structurally-shared `config` actually differ. return useMemo(() => ({ enabled, config, isLoading }), [enabled, config, isLoading]) } |