简体   繁体   English

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

[英]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 完整的例子

The console.log(`is hidden ${isHidden}`); console.log(`is hidden ${isHidden}`); always prints false, and the setIsHidden(true) always gets triggered but never seems to change the state. 总是打印false,并且setIsHidden(true)总是被触发但似乎永远不会改变状态。 Why? 为什么? Basically the isHidden is never setto false, except after the useState initialization. 除了useState初始化之外,isHidden基本上不会设置为false。

Basically what happens is that your useEffect runs only twice on mount and on unmount ( and that's apparently intentional ), however the unwanted side-effect of this is that the value of isHidden that you're checking against in the onScroll method gets closured at it's initial value (which is false ) - forever ( until the unmount that is ). 基本上会发生的事情是你的useEffect在mount和unmount上只运行两次( 这显然是故意的 ),但是这样做的不良副作用是你在onScroll方法中检查的isHidden的值被isHidden了初始值(为false ) - 永远( 直到卸载 )。

You could use functional form of the setter, where it receives the actual value of the state and put all the branching logic inside it. 您可以使用setter的函数形式,它接收状态的实际值并将所有分支逻辑放入其中。 Something like: 就像是:

  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 {
        // ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM