# useNumber _(no submodules)_ ## Purpose `useNumber(value, options?)` formats a number for the active locale via `Intl.NumberFormat`. Memoised on `(resolvedLocale, value, options-hash)` so a no-op re-render does not reach into `Intl.NumberFormat`. Subscribes through `useLocale` so a `setLocale('de-DE')` re-renders consumers with the German thousand-separator on the same React commit cycle as the bus emission. The hook keeps a process-level cache of `Intl.NumberFormat` instances keyed on `(locale, options-hash)`. The first render with a fresh combination pays the constructor cost; subsequent renders (across components, providers, and tests) reuse the cached formatter. ## Features - Memoised on `(locale, value, options-hash)` — no re-format on identical inputs. - Process-level `Intl.NumberFormat` cache — the constructor is paid once per `(locale, options)` combination. - Forwards the full `Intl.NumberFormatOptions` shape (`style`, `notation`, `useGrouping`, `signDisplay`, `minimumFractionDigits`, …). - Production no-Provider fallback uses `'en-GB'` so the hook always returns a real string. - Re-renders on `languageChanged` via the inherited `useLocale` subscription. - `clearUseNumberCache()` exposed for tests / hot-reload scenarios. ## Usage: Basic Example ```tsx import { useNumber } from "@suaveplan/react-i18n"; export function PriceTag(props: { readonly amount: number }) { const formatted = useNumber(props.amount, { style: "decimal", minimumFractionDigits: 2, }); return {formatted}; } ``` ## Usage: Advanced Example The full `Intl.NumberFormatOptions` shape unlocks compact notation, unit display, sign visibility, and per-locale digit grouping. The pattern below shows a stat tile that switches between standard and compact notation depending on magnitude. ```tsx import { useNumber } from "@suaveplan/react-i18n"; export function StatTile(props: { readonly value: number; readonly unit: string; }) { const compact = props.value >= 10_000; const formatted = useNumber(props.value, { style: "unit", unit: props.unit, notation: compact ? "compact" : "standard", compactDisplay: "short", signDisplay: "exceptZero", }); return {formatted}; } ``` ## API Reference ### `useNumber(value: number, options?: Intl.NumberFormatOptions): string` - **Parameters**: - `value` — the numeric value to format. - `options?` — raw `Intl.NumberFormatOptions`. When omitted, the hook uses the locale's default decimal formatting. - **Returns**: the formatted string. - **Throws**: `ReactI18nError(REACT_I18N.NO_PROVIDER)` outside a `` in dev mode (inherited from `useLocale → useI18n`). ### `clearUseNumberCache(): void` Test-only escape hatch to reset the process-level `Intl.NumberFormat` cache. Useful for hot-reload tooling or property-based tests that span thousands of unique option combinations. ## Implementation Notes - The cache is unbounded by design. `Intl.NumberFormat` instances are small (a handful of bytes) and the realistic upper bound on unique `(locale, options-hash)` combinations in a real application is in the dozens, not millions. - The memo key is `(resolvedLocale, value, optionsHash, options)`. The explicit `options` reference is included so consumers who pass the same object across renders share the memo while consumers passing fresh objects with identical contents share via the hash. - The process-level cache is shared across every consumer in the bundle. Two unrelated components requesting `useNumber(x, { style: 'percent' })` in `'en-US'` reach the same cached formatter. - The default locale `'en-GB'` on the no-Provider fallback matches the broader package convention. This keeps the hook from throwing in production while still producing meaningful output.