反应useState,useEffect不能按预期工作

时间:2019-03-31 16:42:11

标签: reactjs react-hooks

我有一个用例,我想用React钩子解决它,但是它没有按我预期的那样工作。

  • 期望:向下滚动时将显示不位于顶部,向后滚动至文档顶部时将消失。
  • 当前:向下滚动时未显示在顶部,但向后滚动至文档顶部时不会消失。 代码沙箱链接:https://codesandbox.io/s/wkroy1r2xl

谢谢。

3 个答案:

答案 0 :(得分:3)

该组件一次添加事件侦听器:仅在安装时。那时,它添加了在该特定时间点被该特定handleScroll值“捕获”的isHeaderMoved侦听器。每当滚动页面时,将被调用的是具有初始isHeaderMoved值的回调。当前的代码基本上一遍又一遍地调用handleScrollfalse

简而言之,您需要添加isHeaderMoved作为效果的依赖项。您还应该在效果中移动handleScroll侦听器,以便钩子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在该主题上的帖子中的这些部分(其中的示例可以比我更好地解释它)

如果有时间的话,有必要仔细阅读整个文章,以全面了解事物。


从skyboxer的评论中,我发现这也行得通,但是我将保留上述所有内容仅供参考。

  useEffect(() => {
    const handleScroll = () => {
      setIsHeaderMoved(window.pageYOffset > 0)
    }

    window.addEventListener("scroll", handleScroll)
    return () => {
      window.removeEventListener("scroll", handleScroll)
    }
  }, [])

答案 1 :(得分:0)

这应该可行,您必须将window.pageYOffsetisHeaderMoved传递给useEffect才能在每次更改时将其触发,如果您将其[]留给它,会开火一次。

  useEffect(
    () => {
      window.addEventListener("scroll", handleScroll);
      return () => {
        window.removeEventListener("scroll", handleScroll);
      };
    },
    [isHeaderMoved]
  );

我认为您也可以使用useRef()来做到这一点。

答案 2 :(得分:0)

我曾经遇到过同样烦人的问题

在父代码中创建组件时尝试在组件上添加一个key prop

<yourcomponent key="some_unique_value" />

这是因为在大多数情况下,特别是当您的组件被重用时,它通常可能仅在进行一些更改时重新渲染,而不是在您重用它时实际再次创建它,基于它的创建方式,因此 {{1 }} 不会被调用。例如在交换机、路由器、循环、条件...

所以添加一个密钥可以防止这种情况发生。如果是在循环中,则需要确保每个元素都是唯一的,如果找不到更好的唯一键,可以在键中包含索引 useEffect