React Context传值时出现Too many re-renders错误的解决方法
解决React Context结合i18n时的无限渲染问题
问题原因分析
你的代码触发"Too many re-renders"无限循环,核心问题有两个:
- i18n初始化逻辑放在组件内部:每次Context组件渲染时,都会重复执行
i18n.init(),这会触发i18n状态变更,进而导致组件重新渲染,形成循环。 - 不必要的状态更新(可选):
onChange里的setCount如果不是业务必需,会额外触发组件渲染,放大循环问题。
具体修复步骤
1. 抽离i18n初始化到独立文件
创建单独的i18n.js文件,把初始化逻辑移到这里,确保全局只执行一次初始化:
// i18n.js import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import translationsEn from './path-to-en-translations'; import translationsBn from './path-to-bn-translations'; i18n .use(initReactI18next) .init({ resources: { en: { translation: translationsEn }, bn: { translation: translationsBn }, }, lng: "bn", fallbackLng: "bn", interpolation: { escapeValue: false }, }); export default i18n;
然后在项目入口文件(比如index.js)引入该文件,完成全局初始化:
// index.js import './i18n'; import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);
2. 优化Context组件逻辑
在Context组件中移除重复初始化逻辑,并缓存Context的value对象,避免不必要的子组件渲染:
// Context.js import React, { createContext, useContext, useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; const LanguageContext = createContext(); export const LanguageProvider = ({ children }) => { const { t, i18n } = useTranslation(); // 如果count不是业务必需,建议直接移除 const [count, setCount] = useState(0); const onChange = (event) => { i18n.changeLanguage(event.target.value); // 非必需的count更新可以删除 setCount(prev => prev + 1); }; // 用useMemo缓存Context值,避免每次渲染创建新对象 const contextValue = useMemo(() => ({ t, onChange, count }), [t, count]); return ( <LanguageContext.Provider value={contextValue}> {children} </LanguageContext.Provider> ); }; export const useLanguage = () => useContext(LanguageContext);
3. 组件中正确使用Context
在Component.js中通过自定义hook获取Context提供的方法:
// Component.js import React from 'react'; import { Select, MenuItem } from '@mui/material'; import { useLanguage } from './Context'; const LanguageSelector = () => { const { onChange } = useLanguage(); return ( <Select defaultValue={"en"} variant="outlined" displayEmpty name="language" notched={false} size="small" onChange={onChange} sx={{ color: "other.white", border: "2px", "&:hover": { border: "2px", }, }} > <MenuItem value="en">English</MenuItem> <MenuItem value="bn">বাংলা</MenuItem> </Select> ); }; export default LanguageSelector;
额外注意事项
- 如果
count状态不是业务必需,直接移除它,减少不必要的状态更新触发的渲染。 - 传递给Context的
value如果是对象或数组,必须用useMemo缓存,避免每次组件渲染都创建新对象,导致所有消费Context的子组件重复渲染。 - 确保
useTranslation的使用符合react-i18next最佳实践,不要在非必要的地方重复调用。
内容的提问来源于stack exchange,提问作者MD. Istiak Shamim Shishir
相关产品推荐
相关产品推荐

