如何在 React Router v7 中为不同地区格式化数字
使用地区特定的分隔符显示数字
问题
世界各地的数字书写方式各不相同。在美国,10,000.5 表示一万零零点五,而在德国则写作 10.000,5——逗号和句号的作用完全对调。这不仅仅是风格或偏好的问题,而是可读性的问题。德国用户看到 10,000.5 可能会把它读作十,忽略分组分隔符。美国用户看到 10.000,5 可能会把它读作一万,忽略小数点。
相同的数字在不同地区的读者眼中可能表达完全相反的含义。如果应用程序在没有考虑地区格式的情况下直接显示原始数字,用户很容易产生误解,甚至对数据的可信度产生怀疑。
解决方案
根据用户的地区格式化数字,遵循本地的千位分隔符和小数点规则。这样可以将数字值转换为用户熟悉的格式,提高可读性和准确性。
React-intl 提供了格式化方法,利用浏览器内置的 Intl.NumberFormat API,自动处理不同地区的数字格式。通过这些格式化器传递数字值,应用程序无需手动处理分隔符逻辑,就能输出符合用户期望的结果。
步骤
1. 使用 useIntl 创建数字格式化组件
useIntl 钩子提供了包括 formatNumber 在内的格式化方法,可以接收数字并返回符合地区格式的字符串。
import { useIntl } from "react-intl";
export default function ProductPrice() {
const intl = useIntl();
const price = 1234.56;
return (
<div>
<p>Price: {intl.formatNumber(price)}</p>
</div>
);
}
formatNumber 方法会根据当前地区自动应用正确的分隔符。例如,地区为 en-US 的用户会看到“1,234.56”,而地区为 de-DE 的用户会看到“1.234,56”。
2. 使用样式选项格式化货币数值
formatNumber 方法接受符合 Intl.NumberFormatOptions 的选项,包括货币格式化。
import { useIntl } from "react-intl";
export default function ProductPrice() {
const intl = useIntl();
const price = 1234.56;
return (
<div>
<p>
{intl.formatNumber(price, {
style: "currency",
currency: "USD",
})}
</p>
</div>
);
}
对于 en-US,会生成 “$1,234.56”;对于 de-DE,会生成 “1.234,56 $”,分别应用了分隔符和货币符号的本地化规范。
3. 使用 FormattedNumber 进行声明式格式化
FormattedNumber 组件提供了声明式的替代方案,支持以 props 方式传递相同的选项。
import { FormattedNumber } from "react-intl";
export default function Statistics() {
const totalUsers = 1500000;
const growthRate = 0.23;
return (
<div>
<p>
Total users: <FormattedNumber value={totalUsers} />
</p>
<p>
Growth rate: <FormattedNumber value={growthRate} style="percent" />
</p>
</div>
);
}
该组件会将格式化后的数字直接渲染到 DOM 中。对于 en-US,显示为 “1,500,000” 和 “23%”;对于 de-DE,显示为 “1.500.000” 和 “23 %”。
4. 从 loader 数据格式化数字
在 React Router 7 中,路由组件可通过 useLoaderData hook 获取 loader 数据。结合数字格式化,可以展示服务器提供的数值。
import { useLoaderData } from "react-router";
import { FormattedNumber } from "react-intl";
export async function loader() {
return {
revenue: 45678.9,
units: 12500,
};
}
export default function Dashboard() {
const { revenue, units } = useLoaderData<typeof loader>();
return (
<div>
<h1>Dashboard</h1>
<p>
Revenue:{" "}
<FormattedNumber value={revenue} style="currency" currency="USD" />
</p>
<p>
Units sold: <FormattedNumber value={units} />
</p>
</div>
);
}
loader 提供原始数值数据,组件会根据用户的本地化设置进行格式化。这样可以将数据获取与展示逻辑解耦。