React JS中如何在useCallback内更新state避免无限循环问题
问题根因
你的无限循环来自依赖链的闭环:
lastDoc变更 →useCallback生成新的getData实例 →useEffect依赖getData触发执行 → 调用getData再次更新lastDoc,循环往复。
解决方案1:使用useRef同步状态(兼容所有React版本)
核心思路是用不需要加入依赖数组的ref存储lastDoc的最新值,既可以拿到最新状态,又不会触发useCallback重新生成:
const [lastDoc, setLastDoc] = useState(null); // 声明ref同步lastDoc的值 const lastDocRef = useRef(lastDoc); // 每次lastDoc变更时更新ref useEffect(() => { lastDocRef.current = lastDoc; }, [lastDoc]); const getData = useCallback(async() => { // 从ref取最新值,不需要把lastDoc加入依赖 const data = await getSomething(lastDocRef.current); setLastDoc(data.lastDoc); // 依赖数组不需要加lastDoc,不会触发重复生成 }, [getSomething]); // 此时useEffect只会在组件初始化时执行一次,不会循环 useEffect(() => { getData(); }, [getData]);
如果是分页加载下一页的场景,直接调用getData即可,ref始终能拿到最新的lastDoc值。
解决方案2:使用React 18+的useEvent(更简洁)
如果你的项目使用React 18及以上版本,可以直接用官方提供的useEvent定义回调,回调内部始终能拿到最新的状态,不需要把状态加入依赖数组:
import { useEvent } from 'react'; const [lastDoc, setLastDoc] = useState(null); // useEvent定义的回调不需要加lastDoc依赖 const getData = useEvent(async() => { const data = await getSomething(lastDoc); setLastDoc(data.lastDoc); }); useEffect(() => { getData(); }, [getData]);
注意:useEvent在React 18的早期版本属于实验性API,确保你使用的React版本已经正式支持该API。
补充说明
不要直接通过注释禁用ESLint的依赖检查,上述两种方案都可以在满足依赖检查规则的前提下解决无限循环问题。
内容的提问来源于stack exchange,提问作者ApplowPi
相关产品推荐
相关产品推荐

