3.8 KiB
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.NumberFormatcache — the constructor is paid once per(locale, options)combination. - Forwards the full
Intl.NumberFormatOptionsshape (style,notation,useGrouping,signDisplay,minimumFractionDigits, …). - Production no-Provider fallback uses
'en-GB'so the hook always returns a real string. - Re-renders on
languageChangedvia the inheriteduseLocalesubscription. clearUseNumberCache()exposed for tests / hot-reload scenarios.
Usage: Basic Example
import { useNumber } from "@suaveplan/react-i18n";
export function PriceTag(props: { readonly amount: number }) {
const formatted = useNumber(props.amount, {
style: "decimal",
minimumFractionDigits: 2,
});
return <span>{formatted}</span>;
}
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.
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 <strong>{formatted}</strong>;
}
API Reference
useNumber(value: number, options?: Intl.NumberFormatOptions): string
- Parameters:
value— the numeric value to format.options?— rawIntl.NumberFormatOptions. When omitted, the hook uses the locale's default decimal formatting.
- Returns: the formatted string.
- Throws:
ReactI18nError(REACT_I18N.NO_PROVIDER)outside a<TranslationProvider>in dev mode (inherited fromuseLocale → 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.NumberFormatinstances 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 explicitoptionsreference 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.