# 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.