You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:45:38