如何在i18next配置中使用React Query?遇Hook使用限制问题求助
在React中结合i18next与React Query实现本地化的解决方案
我在React应用中使用i18next实现本地化,原本通过API获取翻译响应数据,现在想改用React Query调用API,但React Query的Hook仅能在函数组件或自定义Hook中调用,直接在i18n配置里调用会触发错误:React Hook "useQuery" is called in a function that is not a React function component or custom React Hook function。
原有i18n配置代码
获取本地化数据的函数:
export const getLocalisation = async (lng: string) => { try { const localisationResponse = await axios.get( `/localisation/${lng}` ); return localisationResponse; } catch (err) { console.log('Error at getLocalisation: ', err); } };
i18n初始化配置:
const backendOptions = { allowMultiLoading: true, loadPath: `/localisation/en`, request: (options: any, url: any, payload: any, callback: any) => { try { getLocalisation(EN).then((result) => { callback(null, { data: result?.data, status: STATUS_CODE_200 }); }); } catch (e) { console.error(e); callback(e); // Passing `e` will handle error status code } } }; i18n .use(HttpBackend) .use(LanguageDetector) .use(initReactI18next) .init({ debug: false, fallbackLng: EN, supportedLngs: [EN], ns: [], partialBundledLanguages: true, interpolation: { escapeValue: false }, backend: backendOptions }); export default i18n;
解决方案
通过自定义Hook封装React Query逻辑,在组件内部获取翻译数据后手动注入i18next,完全符合Hook使用规则:
- 创建自定义Hook封装React Query请求
import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; export const useLocalisation = (lng: string) => { return useQuery({ queryKey: ['localisation', lng], // 用语言标识作为查询键,确保不同语言缓存独立 queryFn: async () => { const response = await axios.get(`/localisation/${lng}`); return response.data; }, staleTime: Infinity, // 翻译数据更新频率低,设置永久缓存 retry: 2, // 失败自动重试2次 }); };
- 修改i18n基础配置(移除自定义Backend)
// i18n.js import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; i18n .use(LanguageDetector) .use(initReactI18next) .init({ debug: false, fallbackLng: 'en', supportedLngs: ['en'], ns: ['translation'], // 指定命名空间,和后续添加资源对应 partialBundledLanguages: true, interpolation: { escapeValue: false }, // 不再配置自定义backend,改为手动注入翻译数据 }); export default i18n;
- 在根组件中获取数据并注入i18next
import { useLocalisation } from './useLocalisation'; import i18n from './i18n'; import { useEffect } from 'react'; function App() { const { data: translations, isSuccess, isLoading } = useLocalisation(i18n.language); // 当翻译数据加载成功后,注入到i18next useEffect(() => { if (isSuccess && translations) { i18n.addResourceBundle( i18n.language, 'translation', translations, true, // 覆盖已有资源 true // 启用资源 ); } }, [translations, isSuccess]); // 加载状态处理 if (isLoading) { return <div>加载翻译资源中...</div>; } return ( <div className="app"> {/* 示例:使用翻译文本 */} <h1>{i18n.t('welcome')}</h1> </div> ); } export default App;
- 处理语言切换场景
如果需要支持多语言切换,只需在语言切换组件中复用自定义Hook,React Query会自动根据新语言获取数据并更新缓存:
import { useLocalisation } from './useLocalisation'; import i18n from './i18n'; import { useEffect } from 'react'; function LanguageSwitcher() { const changeLanguage = async (lng: string) => { await i18n.changeLanguage(lng); }; const { data: translations, isSuccess } = useLocalisation(i18n.language); useEffect(() => { if (isSuccess && translations) { i18n.addResourceBundle(i18n.language, 'translation', translations, true, true); } }, [translations, isSuccess]); return ( <div className="language-switcher"> <button onClick={() => changeLanguage('en')}>English</button> <button onClick={() => changeLanguage('zh-CN')}>简体中文</button> </div> ); } export default LanguageSwitcher;
方案优势
- 完全遵循React Hook使用规则,避免报错
- 利用React Query的缓存、重试、背景刷新等特性,提升翻译数据的可靠性
- 灵活支持语言切换,自动适配不同语言的翻译资源
内容的提问来源于stack exchange,提问作者Parvez Shaikh
相关产品推荐
相关产品推荐

