反应钩子。为什么不设置功能改变状态?

React hooks. Why doesn't set function change state?

const Navbar = () => {
  const prevScrollY = React.useRef<number>();

  const [isHidden, setIsHidden] = React.useState(false);

  React.useEffect(() => {
    const onScroll = () => {
      const scrolledDown = window.scrollY > prevScrollY.current!;
      console.log(`is hidden ${isHidden}`);
      if (scrolledDown && !isHidden) {
        setIsHidden(true);
        console.log(`set hidden true`);
      } else if (!scrolledDown && isHidden) {
        console.log(`set hidden false. THIS NEVER HAPPENS`);
        setIsHidden(false);
      }

      prevScrollY.current = window.scrollY;
    };

    console.log("adding listener");

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

  return isHidden ? null : <div>navbar</div>;
};

Full example

console.log(`is hidden ${isHidden}`); 总是打印 false,而 setIsHidden(true) 总是被触发但似乎永远不会改变状态。为什么?基本上 isHidden 永远不会设置为 false,除非在 useState 初始化之后。

基本上发生的事情是你的 useEffect 在挂载和卸载时只运行两次(这显然是故意的),但是这样做的副作用是您在 onScroll 方法中检查的 isHidden 的值在其初始值(即 false)处关闭 - 永远(直到卸载是).

您可以使用 setter 的函数形式,它接收状态的实际值并将所有分支逻辑放入其中。类似于:

  setIsHidden(isHidden => { // <- this will be the proper one
     const scrolledDown = window.scrollY > prevScrollY.current!;
     console.log(`is hidden ${isHidden}`);
     if (scrolledDown && !isHidden) {
        console.log(`set hidden true`);
        return true;  
      } else if (!scrolledDown && isHidden) {
        console.log(`set hidden false. THIS NEVER HAPPENS`);
        return false;
      } else {
        // ...