如何在 React Router v7 中为不同区域设置格式化日期
以区域特定的格式显示日期
问题
日期没有统一的书写格式。数字序列 10/12/2025 在美国表示 10 月 12 日,但在英国表示 12 月 10 日。即使是像 "Oct 12, 2025" 这样的格式,也假设了英语的月份名称和特定的排列顺序,这可能与用户的期望不符。当应用程序以单一固定格式显示日期时,对于遵循不同惯例的地区用户来说,会显得陌生,从而降低清晰度和信任感。
不同的语言环境对日期呈现有不同的规则,包括日、月、年的顺序,分隔符的选择,以及月份名称是全写还是缩写。忽视这些惯例会迫使用户在脑海中将日期转换为他们熟悉的格式,从而增加认知负担和误解的风险。
解决方案
根据用户的语言环境格式化日期值,将显示逻辑委托给理解区域惯例的国际化 API。与其手动构建日期字符串,不如将日期对象传递给格式化函数或组件,这些函数或组件会根据活动语言环境应用正确的顺序、分隔符和月份名称。
React-intl 提供了声明式组件和命令式方法,这些方法接受标准的日期格式选项并生成符合语言环境的字符串。通过指定要包含的日期部分及其详细程度,您可以控制输出样式,而库会处理区域差异。这种方法将日期格式化逻辑与显示组件分离,并确保整个应用程序的一致性。
步骤
1. 使用 FormattedDate 在组件中格式化日期
使用 react-intl 的 FormattedDate 组件以语言环境特定的格式渲染日期。该组件接受一个日期值和与 Intl.DateTimeFormatOptions 对应的格式选项。
import { FormattedDate } from "react-intl";
export default function EventCard({ event }) {
return (
<article>
<h2>{event.title}</h2>
<time>
<FormattedDate
value={event.date}
year="numeric"
month="long"
day="numeric"
/>
</time>
<p>{event.description}</p>
</article>
);
}
FormattedDate 组件使用 formatDate 和 Intl.DateTimeFormat API 生成与周围 IntlProvider 提供的语言环境匹配的字符串。year、month 和 day 选项控制显示的部分及其格式。
2. 使用 useIntl 以命令式格式化日期
使用 useIntl 钩子访问 formatDate 方法,当您需要为非渲染上下文(如属性、aria 标签或数据转换)生成格式化的日期字符串时。
import { useIntl } from "react-intl";
export default function EventList({ events }) {
const intl = useIntl();
return (
<ul>
{events.map((event) => {
const formattedDate = intl.formatDate(event.date, {
year: "numeric",
month: "short",
day: "numeric",
});
return (
<li key={event.id}>
<a
href={`/events/${event.id}`}
aria-label={`${event.title} on ${formattedDate}`}
>
{event.title}
</a>
</li>
);
})}
</ul>
);
}
formatDate 函数接受一个日期值和可选的 Intl.DateTimeFormatOptions,并返回一个按语言环境格式化的字符串。当格式化日期需要嵌入到另一个字符串中或用作属性值时,这非常有用。
3. 创建可重用的日期格式化助手
将常见的日期格式化模式提取到一个包装 intl.formatDate 的助手函数中,以确保整个应用程序的一致性。
import { useIntl } from "react-intl";
export function useDateFormatter() {
const intl = useIntl();
return {
formatShortDate: (date: Date | number) =>
intl.formatDate(date, {
year: "numeric",
month: "numeric",
day: "numeric",
}),
formatLongDate: (date: Date | number) =>
intl.formatDate(date, {
year: "numeric",
month: "long",
day: "numeric",
}),
formatDateTime: (date: Date | number) =>
intl.formatDate(date, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
}),
};
}
此钩子集中格式化逻辑,并使整个应用程序中应用一致的日期样式变得容易。组件根据所需的详细程度调用适当的方法。
4. 在路由加载器中格式化日期
在数据加载期间需要格式化日期时,可以从请求中获取区域设置,并使用 createIntl 在返回加载器数据之前格式化日期。
import type { Route } from "./+types/event";
import { createIntl, createIntlCache } from "react-intl";
const cache = createIntlCache();
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const locale = url.searchParams.get("locale") || "en";
const event = await fetchEvent();
const intl = createIntl({ locale, messages: {} }, cache);
return {
event,
formattedDate: intl.formatDate(event.date, {
year: "numeric",
month: "long",
day: "numeric",
}),
};
}
export default function Event({ loaderData }: Route.ComponentProps) {
return (
<article>
<h1>{loaderData.event.title}</h1>
<time>{loaderData.formattedDate}</time>
</article>
);
}
createIntl 函数创建了一个 intl 对象,可以在 React 组件之外格式化日期。这种方法在服务器端或静态生成期间预格式化日期,从而减少了客户端的工作量。