Javascript 如何在useEffect中使用useState?
我试图将我的组件从react.component重构为hook,但遇到了一些麻烦。我真的不明白如何使用我的状态补偿。该值已设置,或者在需要时未设置 第一次尝试:Javascript 如何在useEffect中使用useState?,javascript,reactjs,react-hooks,next.js,Javascript,Reactjs,React Hooks,Next.js,我试图将我的组件从react.component重构为hook,但遇到了一些麻烦。我真的不明白如何使用我的状态补偿。该值已设置,或者在需要时未设置 第一次尝试: const [offsetTop, setOffsetTop] = useState(); useEffect(() => { setOffsetTop(window.pageYOffset + document.querySelector(".projectsContainer").getBound
const [offsetTop, setOffsetTop] = useState();
useEffect(() => {
setOffsetTop(window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top)
console.log(offsetTop);
window.addEventListener('scroll', handleScroll, true)
return () => window.removeEventListener("scroll", handleScroll);
}, []);
我还尝试将它与第二个方法useEffect一起使用,并将[offsetTop]作为第二个参数,但我的日志显示了两次,其中包含unde和值。我理解为什么它显示了两次,但仍然不能解决我的问题,我的情况不起作用
第二次尝试:
const [offsetTop, setOffsetTop] = useState();
useEffect(() => {
setOffsetTop(window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top)
}, []);
useEffect(() => {
console.log(offsetTop);
window.addEventListener('scroll', handleScroll, true)
return () => window.removeEventListener("scroll", handleScroll);
}, [offsetTop]);
handleScroll功能:
功能手柄{
console.logoffsetTop;
const scrolledY=window.scrollY
如果滚动Y>offsetTop console.logworks
}
与第一次尝试相同的代码:放在componentDidMount{}中,使用它可以很好地工作。因此,情况并不坏。这是关于何时设置值以及useState和useEffect如何工作的问题。您的条件在第一个变量中不起作用吗?这看起来是正确的,在这种情况下,console.logoffsetTop不应该打印新设置的值,而是之前设置的值。要按照您的意愿记录,您需要: const[offsetTop,setOffsetTop]=useState; useEffect=>{ setOffsetTopwindow.pageYOffset+document.querySelector.projectsContainer.getBoundingClientRect.top window.addEventListener'scroll',handleScroll,真 return=>window.removeEventListenerscroll,handleScroll; }, []; useEffect=>{ console.logoffsetTop; },[offsetTop]; 第二次尝试的问题是它会执行以下操作: 第一次渲染: 第一次使用效果设置新的偏移 第二次使用效果火与旧的偏置 偏移更新导致重新渲染 第二个useEffect进行清理,删除事件侦听器 我猜,在这里的某个地方,浏览器传播事件,而你的听众不见了 第二次useEffect使用新的offsetTop再次激发,并再次设置侦听器,但它已经错过了事件 啊。。。那只是你问题的一部分 问题的第二部分是handleScroll有效地从创建偏移值并将其设置为侦听器的渲染周期捕获偏移值。应该使用useRef使handleScroll与当前值保持同步,如果出于其他原因不需要offsetTop,则根本不需要使用state。你可以做: const{current:heap}=useRef{ 偏移量:0, }; useEffect=>{ 功能手柄{ console.logheap.offsetTop; const scrolledY=window.scrollY ifscrolledY>heap.offsetTop console.logworks } heap.offsetTop=window.pageYOffset+document.querySelector.projectscocontainer.getBoundingClientRect.top; window.addEventListener'scroll',handleScroll,真 return=>window.removeEventListenerscroll,handleScroll; //堆在重新渲染时保证为同一对象, //因此,将其包含在下面的依赖项中不会产生任何影响 //重新计算。但是,如果不包括它,请使用ESLint //为了检查代码错误,它会抱怨堆不存在 //作为缺少的依赖项。 },[heap];
这样,offsetTop在重新渲染时是持久的,handleScroll始终使用当前值。如果您还需要在offsetTop更新时重新渲染,那么您还可以使用useState触发重新渲染,例如,也可以将offsetTop值注入渲染组件。这让我觉得您可能根本不需要状态。为什么不根据需要导出offsetTop的值
useEffect(() => {
function handleScroll() {
const scrolledY = window.scrollY;
const offsetTop = window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top;
if(scrolledY > offsetTop) console.log("works")
}
window.addEventListener('scroll', handleScroll, true)
return () => window.removeEventListener("scroll", handleScroll, true);
}, []);
然而,也许你的想法是,你想要捕获offsetTop的初始值,然后在事情发生变化时使用它。在这种情况下,我认为您的主要问题是由于removeEventListener没有正确清理,因为您没有传递与addEventListener相同的参数missing true。因此,仍然有一个handleScroll实例保存第一次渲染的offsetTop的初始值,我认为这就是为什么您会看到未定义被记录的原因
错误的❌
正当✅
复制:您确定吗。当useEffect运行时,可以查询projectsContainer吗?为了确保它是正确的,您可以改为尝试,它在所有DOM变异后同步运行。您的右变体有这个问题:它在每次更新offsetTop时删除并重新添加事件侦听器,这在性能上是不好的,当删除前一个侦听器时,在这两个更新之间也会错过一些更新,但新的侦听器尚未添加。removeEventListener的参数很好。。必须与addEventListener的匹配..-我错过了:
useEffect(() => {
setOffsetTop(window.pageYOffset +
document.querySelector(".projectsContainer").getBoundingClientRect().top;);
}, []);
useEffect(() => {
// The first time this useEffect runs, the value of `offsetTop`
// is still the initial value of undefined.
function handleScroll() {
console.log(offsetTop)
const scrolledY = window.scrollY;
if (scrolledY > offsetTop) console.log("works");
}
window.addEventListener("scroll", handleScroll, true);
// This doesn't get removed correctly
// because you don't pass the same parameters (missing `true`)
return () => window.removeEventListener("scroll", handleScroll);
}, [offsetTop]);
useEffect(() => {
setOffsetTop(window.pageYOffset +
document.querySelector(".projectsContainer").getBoundingClientRect().top;);
}, []);
useEffect(() => {
function handleScroll() {
const scrolledY = window.scrollY;
if (scrolledY > offsetTop) console.log("works");
}
window.addEventListener("scroll", handleScroll, true);
return () => window.removeEventListener("scroll", handleScroll, true);
}, [offsetTop]);