反应 useState,useEffect 没有按预期工作
React useState, useEffect not working as expected
我有一个用例,我想用 React hooks 解决它,但它没有像我预期的那样工作。
- 期望:向下滚动时显示不在顶部,返回文档顶部时消失。
- 当前:向下滚动时不在顶部显示,但在向后滚动到文档顶部时不会消失。
代码沙箱 link:https://codesandbox.io/s/wkroy1r2xl
提前致谢。
这应该有效,你必须将 window.pageYOffset
或 isHeaderMoved
传递给 useEffect
以在每次更改时触发它,如果你离开它 []
它会触发一次。
useEffect(
() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
},
[isHeaderMoved]
);
我想你也可以使用 useRef()
来做到这一点。
该组件添加一次事件监听器:仅在挂载时。那时,它会在那个特定的时间点添加 "captured" 的 handleScroll
侦听器和那个特定的 isHeaderMoved
值。每当页面滚动时,将调用的回调是具有初始 isHeaderMoved
值的回调。当前的代码基本上一遍又一遍地调用 handleScroll
和 false
。
总之,需要对效果添加isHeaderMoved
作为依赖。您还应该将 handleScroll
侦听器移动到效果中,以便 hooks eslint 插件可以更正确地跟踪它的依赖关系。
useEffect(
() => {
const handleScroll = () => {
if (window.pageYOffset > 0) {
if (!isHeaderMoved) {
setIsHeaderMoved(true)
}
} else if (isHeaderMoved) {
setIsHeaderMoved(false)
}
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
},
[isHeaderMoved],
)
请参阅 Dan Abromov 关于该主题的 post 中的这些部分(其中的示例比我能更好地解释它):
- https://overreacted.io/a-complete-guide-to-useeffect/#each-render-has-its-own-event-handlers
- https://overreacted.io/a-complete-guide-to-useeffect/#each-render-has-its-own-effects
- https://overreacted.io/a-complete-guide-to-useeffect/#moving-functions-inside-effects
如果你有时间,值得通读整个post以充分理解事物。
根据 skyboxer 的评论,我想到这也可以,但我会保留以上所有内容以供参考。
useEffect(() => {
const handleScroll = () => {
setIsHeaderMoved(window.pageYOffset > 0)
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
}, [])
我曾经遇到过同样烦人的问题
尝试在父代码中创建组件时在组件上添加一个 key prop
<yourcomponent key="some_unique_value" />
这是因为在大多数情况下,尤其是当您的组件被重用时,它通常可能仅在进行一些更改后重新呈现,而不是在您重用它时根据其创建方式实际再次创建它,因此 useEffect
不会被调用。例如在交换机、路由器、循环、条件...
因此添加密钥将防止这种情况发生。如果它在一个循环中,您需要确保每个元素都是唯一的,如果找不到更好的唯一键,可以在键中包含索引 i
。
我有一个用例,我想用 React hooks 解决它,但它没有像我预期的那样工作。
- 期望:向下滚动时显示不在顶部,返回文档顶部时消失。
- 当前:向下滚动时不在顶部显示,但在向后滚动到文档顶部时不会消失。 代码沙箱 link:https://codesandbox.io/s/wkroy1r2xl
提前致谢。
这应该有效,你必须将 window.pageYOffset
或 isHeaderMoved
传递给 useEffect
以在每次更改时触发它,如果你离开它 []
它会触发一次。
useEffect(
() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
},
[isHeaderMoved]
);
我想你也可以使用 useRef()
来做到这一点。
该组件添加一次事件监听器:仅在挂载时。那时,它会在那个特定的时间点添加 "captured" 的 handleScroll
侦听器和那个特定的 isHeaderMoved
值。每当页面滚动时,将调用的回调是具有初始 isHeaderMoved
值的回调。当前的代码基本上一遍又一遍地调用 handleScroll
和 false
。
总之,需要对效果添加isHeaderMoved
作为依赖。您还应该将 handleScroll
侦听器移动到效果中,以便 hooks eslint 插件可以更正确地跟踪它的依赖关系。
useEffect(
() => {
const handleScroll = () => {
if (window.pageYOffset > 0) {
if (!isHeaderMoved) {
setIsHeaderMoved(true)
}
} else if (isHeaderMoved) {
setIsHeaderMoved(false)
}
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
},
[isHeaderMoved],
)
请参阅 Dan Abromov 关于该主题的 post 中的这些部分(其中的示例比我能更好地解释它):
- https://overreacted.io/a-complete-guide-to-useeffect/#each-render-has-its-own-event-handlers
- https://overreacted.io/a-complete-guide-to-useeffect/#each-render-has-its-own-effects
- https://overreacted.io/a-complete-guide-to-useeffect/#moving-functions-inside-effects
如果你有时间,值得通读整个post以充分理解事物。
根据 skyboxer 的评论,我想到这也可以,但我会保留以上所有内容以供参考。
useEffect(() => {
const handleScroll = () => {
setIsHeaderMoved(window.pageYOffset > 0)
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
}, [])
我曾经遇到过同样烦人的问题
尝试在父代码中创建组件时在组件上添加一个 key prop
<yourcomponent key="some_unique_value" />
这是因为在大多数情况下,尤其是当您的组件被重用时,它通常可能仅在进行一些更改后重新呈现,而不是在您重用它时根据其创建方式实际再次创建它,因此 useEffect
不会被调用。例如在交换机、路由器、循环、条件...
因此添加密钥将防止这种情况发生。如果它在一个循环中,您需要确保每个元素都是唯一的,如果找不到更好的唯一键,可以在键中包含索引 i
。