为什么useState钩子在useEffect绑定的滚动回调中无法更新状态?
问题原因
- 闭包陷阱导致读取的永远是旧状态
你绑定scroll事件的useEffect依赖数组为空,只会在组件首次挂载时执行一次,绑定的handleScroll函数是首次渲染时创建的,它内部捕获的isFocused永远是初始值false,哪怕后续状态更新,事件回调里拿到的还是旧值,不会同步更新。 - React状态更新是异步的
调用setIsFocused(true)后,状态不会在当前执行上下文立刻生效,所以紧接着写的console.log(isFocused)拿到的还是更新前的旧值,并不是状态没有更新成功,只是打印时机不对。
解决方案
方案1:调整事件绑定的依赖项
把isFocused加入useEffect的依赖数组,每次isFocused变化时重新绑定最新的handleScroll函数,同时单独监听状态变化触发打印:
import React, { useEffect, useRef, useState } from "react"; const SectionII = (props) => { const sectionRef = useRef(); const [isFocused, setIsFocused] = useState(false); const handleScroll = () => { const section = sectionRef.current; if (!section) return; const { y } = section.getBoundingClientRect(); if(!isFocused && y <= 0) { setIsFocused(true); } }; // 监听isFocused更新,状态变化后再打印 useEffect(() => { if (isFocused) { console.log(true); } }, [isFocused]); // 依赖项加入isFocused,每次状态变化重新绑定最新的回调 useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [isFocused]); return ( <section id="mentorship" ref={sectionRef} style={{borderTop: "1px solid"}}> <h1>Section 2</h1> <button>Set hash</button> </section> ); }; export default SectionII;
方案2:用ref存储触发标记(更简洁,性能更好)
如果只需要触发一次打印,不需要用状态存储标记,直接用可变的ref存触发状态即可,不受闭包影响,也不需要重复绑定事件:
import React, { useEffect, useRef } from "react"; const SectionII = (props) => { const sectionRef = useRef(); const hasTriggered = useRef(false); // 用ref存是否已经触发过打印 const handleScroll = () => { const section = sectionRef.current; if (!section || hasTriggered.current) return; const { y } = section.getBoundingClientRect(); if(y <= 0) { hasTriggered.current = true; console.log(true); } }; useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); return ( <section id="mentorship" ref={sectionRef} style={{borderTop: "1px solid"}}> <h1>Section 2</h1> <button>Set hash</button> </section> ); }; export default SectionII;
内容的提问来源于stack exchange,提问作者Lord Reptilia
相关产品推荐
相关产品推荐

