如何结合React Suspense与Trans组件实现翻译内容异步加载?
如何在Trans组件中实现翻译文本内异步加载内容
我希望实现翻译句子中部分内容的异步加载,尝试使用Trans组件但运行时出现错误:
Unhandled Runtime Error
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
我的尝试代码如下:
"use client"; import { Suspense } from "react"; import { Trans } from "react-i18next"; const mockedFetch = (delay: number) => { return new Promise<string>((resolve) => { setTimeout(() => { const last4DigitsOfCard = "3423"; resolve(last4DigitsOfCard); }, delay); }); }; function PersonalizedNumber() { const delay = 2_000; const sentencePromise = mockedFetch(delay); return sentencePromise; // 这里直接返回Promise,导致报错 } function Loading() { return <div>Loading...</div>; } function Last4DigitsOfCard() { return ( <Suspense fallback={<Loading />}> <PersonalizedNumber /> </Suspense> ); } export function YourPrepaidCardEndingInLastFour({ locale, }: { locale: string; }) { return ( <Trans locale={locale} i18nKey="yourPrepaidCardIsReady" components={{ last4DigitsOfCard: <Last4DigitsOfCard />, }} /> ); }
翻译键值:
"yourPrepaidCardIsReady": "Your prepaid card ending in <last4DigitsOfCard/> is active and ready to use."
问题原因
PersonalizedNumber组件直接返回了Promise,而React组件的返回值必须是React元素、null或字符串,不能是Promise。Suspense需要配合能抛出Promise的异步数据逻辑,而非组件直接返回Promise。
解决方法
使用React 18+的use钩子(仅支持客户端组件),它可以直接处理Promise,在Promise pending时自动抛出Promise触发Suspense的fallback,resolved后返回数据。修改后的代码如下:
"use client"; import { Suspense, use } from "react"; import { Trans } from "react-i18next"; const mockedFetch = (delay: number) => { return new Promise<string>((resolve) => { setTimeout(() => { const last4DigitsOfCard = "3423"; resolve(last4DigitsOfCard); }, delay); }); }; function PersonalizedNumber() { const delay = 2_000; // 使用use钩子处理异步Promise,pending时自动触发Suspense const last4Digits = use(mockedFetch(delay)); // 返回React元素而非Promise return <span>{last4Digits}</span>; } function Loading() { return <div>Loading...</div>; } function Last4DigitsOfCard() { return ( <Suspense fallback={<Loading />}> <PersonalizedNumber /> </Suspense> ); } export function YourPrepaidCardEndingInLastFour({ locale, }: { locale: string; }) { return ( <Trans locale={locale} i18nKey="yourPrepaidCardIsReady" components={{ last4DigitsOfCard: <Last4DigitsOfCard />, }} /> ); }
关键修改点
- 引入React的
use钩子,用它处理异步请求的Promise PersonalizedNumber组件不再返回Promise,而是返回包裹异步数据的<span>元素use钩子会自动处理Promise的pending状态:当Promise未完成时,抛出Promise让上层Suspense捕获并显示loading;当Promise resolved后,返回数据并渲染
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

