如何在使用i18next时处理ESLint react-hooks exhaustive-deps规则?
问题解答
1. 语言切换时代码会重新执行吗?
会。useTranslation返回的t函数会随着语言环境切换更新引用或内部关联状态,而你的useEffect依赖数组包含t,所以当t变化时,useEffect会重新触发,进而再次调用getUser发起Ajax请求。
2. 如何避免语言切换触发重复Ajax请求?
核心是让useEffect的依赖数组不包含t,同时保证错误提示能跟随语言切换更新,以下是两种实用方案:
方案一:将翻译逻辑移到渲染阶段
不在useEffect内直接调用t生成翻译文本,而是存储错误提示的key,在渲染时再用t转换:
const { t } = useTranslation(); const [textErrorKey, setTextErrorKey] = useState(); const [loading, setLoading] = useState(false); const [user, setUser] = useState(null); useEffect(() => { async function getUser() { setLoading(true); try { const { user } = await queryUser(userId); setUser(user); setTextErrorKey(undefined); // 请求成功清空错误 } catch(error) { if(!error.isAuthenticated) { setTextErrorKey('not-authenticated'); // 仅存储错误key } } finally { setLoading(false); // 无论成功失败都关闭loading } } if (id) { getUser(); } }, [id]) // 依赖仅保留id,移除t // 渲染阶段进行翻译 return ( <div> {loading && <div>加载中...</div>} {textErrorKey && <div>{t(textErrorKey)}</div>} {/* 其他渲染内容 */} </div> )
语言切换时,t函数更新会直接触发渲染文本更新,不会重新发起请求。
方案二:用useRef保存最新的t引用
如果必须在useEffect内处理翻译,可通过useRef同步最新的t函数,避免将t加入依赖数组:
const { t } = useTranslation(); const tRef = useRef(t); const [textErrorKey, setTextErrorKey] = useState(); const [loading, setLoading] = useState(false); const [user, setUser] = useState(null); // 同步最新的t到ref useEffect(() => { tRef.current = t; }, [t]) useEffect(() => { async function getUser() { setLoading(true); try { const { user } = await queryUser(userId); setUser(user); setTextErrorKey(undefined); } catch(error) { if(!error.isAuthenticated) { // 使用ref.current获取最新的t函数 setTextErrorKey(tRef.current('not-authenticated')); } } finally { setLoading(false); } } if (id) { getUser(); } }, [id]) // 依赖仅保留id
3. react-hook/exhaustive-deps规则的常见最佳实践
- 拆分渲染与副作用逻辑:将依赖渲染上下文(如翻译、主题)的逻辑从副作用(如数据请求)中剥离,让副作用只处理数据操作,渲染时再做上下文相关转换。
- 用useRef稳定频繁变化的引用:对于
t、组件内工具函数这类可能频繁变化但无需触发副作用更新的值,用useRef保存最新引用,副作用中通过ref.current访问。 - 用useCallback/useMemo稳定依赖引用:副作用依赖的组件内函数用
useCallback包裹,计算值用useMemo缓存,确保引用稳定,避免不必要的副作用触发。 - 谨慎禁用规则:仅当明确某值变化不影响副作用逻辑时,才用
// eslint-disable-next-line react-hooks/exhaustive-deps禁用规则,且必须添加注释说明原因。 - 理解浅比较逻辑:React对依赖数组元素做浅比较,避免在依赖数组中传入匿名函数、对象字面量这类每次渲染都会生成新引用的值,尽量依赖稳定的状态、props或处理后的稳定引用。
内容的提问来源于stack exchange,提问作者kitimenpolku
相关产品推荐
相关产品推荐

