React中useState更新后的值在useEffect内无法获取的问题
问题解决:IntersectionObserver回调中无法获取更新后的useState值
问题描述
我声明了一个useState状态:
const [started, setStarted] = useState(false);
点击函数中调用setStarted(true)更新状态,但在依赖项为空的useEffect里创建的IntersectionObserver回调中,started始终是false,控制台输出也一直显示false,导致功能无法正常运行。代码如下:
let options = { rootMargin: "0px", threshold: [0.5, 0.5] }; useEffect(() => { let handleStart = (entries) => { entries.forEach((entry) => { if (started) { //do something } console.log("started value " + started); }); }; let observer = new IntersectionObserver(handleStart, options); observer.observe(currentRef.current); }, []);
原因分析
这是典型的闭包陷阱:依赖为空的useEffect只会在组件挂载时执行一次,此时handleStart回调捕获的是started的初始值(false)。后续即使通过setStarted更新了状态,回调函数里引用的还是旧的闭包值,不会同步获取最新的started。
解决方案
方案1:将started加入useEffect依赖项
把started添加到useEffect的依赖数组中,这样每次started变化时,useEffect会重新执行,创建新的handleStart回调以捕获最新的started值。同时要添加清理函数,避免重复观察导致内存泄漏:
let options = { rootMargin: "0px", threshold: [0.5, 0.5] }; useEffect(() => { const handleStart = (entries) => { entries.forEach((entry) => { if (started) { //do something } console.log("started value " + started); }); }; const observer = new IntersectionObserver(handleStart, options); const target = currentRef.current; if (target) { observer.observe(target); } // 清理函数:组件卸载或依赖变化时停止观察 return () => { if (target) { observer.unobserve(target); } }; }, [started]); // 将started加入依赖数组
方案2:使用useRef保存最新状态
如果不想频繁重建IntersectionObserver,可以用useRef来存储started的最新值。ref的current属性是可变的,能在闭包中访问到最新状态,只需额外加一个useEffect同步state和ref:
const [started, setStarted] = useState(false); const startedRef = useRef(started); // 同步state到ref,确保ref始终保存最新值 useEffect(() => { startedRef.current = started; }, [started]); let options = { rootMargin: "0px", threshold: [0.5, 0.5] }; useEffect(() => { const handleStart = (entries) => { entries.forEach((entry) => { // 访问ref的current获取最新的started值 if (startedRef.current) { //do something } console.log("started value " + startedRef.current); }); }; const observer = new IntersectionObserver(handleStart, options); const target = currentRef.current; if (target) { observer.observe(target); } return () => { if (target) { observer.unobserve(target); } }; }, []); // 依赖仍为空,无需频繁重建observer
内容的提问来源于stack exchange,提问作者user3253146
相关产品推荐
相关产品推荐

