React Hooks, how to implement useHideOnScroll hook?2019 Community Moderator ElectionReact hooks. Why doesn't set function change state?How to declare global variables in Android?Loop inside React JSXReact js onClick can't pass value to methodWhat is the difference between using constructor vs getInitialState in React / React Native?What do these three dots in React do?Programmatically navigate using react routerWhat is the difference between React Native and React?How to prevent child component from re-rendering when using React hooks and memo?React Hooks - How do I implement shouldComponentUpdate?Detect click outside React component using hooks

How to make sure I'm assertive enough in contact with subordinates?

What does "rhumatis" mean?

Split a number into equal parts given the number of parts

How do we objectively assess if a dialogue sounds unnatural or cringy?

Practical reasons to have both a large police force and bounty hunting network?

What is the oldest European royal house?

PTiJ: How should animals pray?

Can inspiration allow the Rogue to make a Sneak Attack?

Remove object from array based on array of some property of that object

Is this nominative case or accusative case?

The past tense for the quoting particle って

Does the in-code argument passing conventions used on PDP-11's have a name?

Under what conditions would I NOT add my Proficiency Bonus to a Spell Attack Roll (or Saving Throw DC)?

“I had a flat in the centre of town, but I didn’t like living there, so …”

What is Tony Stark injecting into himself in Iron Man 3?

Why would the IRS ask for birth certificates or even audit a small tax return?

If nine coins are tossed, what is the probability that the number of heads is even?

Why aren't there more gauls like Obelix?

What's the best tool for cutting holes into duct work?

The need of reserving one's ability in job interviews

Was it really inappropriate to write a pull request for the company I interviewed with?

Are there other characters in the Star Wars universe who had damaged bodies and needed to wear an outfit like Darth Vader?

The Key to the Door

Why can't we use freedom of speech and expression to incite people to rebel against government in India?



React Hooks, how to implement useHideOnScroll hook?



2019 Community Moderator ElectionReact hooks. Why doesn't set function change state?How to declare global variables in Android?Loop inside React JSXReact js onClick can't pass value to methodWhat is the difference between using constructor vs getInitialState in React / React Native?What do these three dots in React do?Programmatically navigate using react routerWhat is the difference between React Native and React?How to prevent child component from re-rendering when using React hooks and memo?React Hooks - How do I implement shouldComponentUpdate?Detect click outside React component using hooks










1















const shouldHide = useHideOnScroll();
return shouldHide ? null : <div>something</div>


The useHideOnScroll behaviour should return updated value not on every scroll but only when there is a change.



The pseudo logic being something like the following:



if (scrolledDown && !isHidden) 
setIsHidden(true);
else if (scrolledUp && isHidden)
setIsHidden(false);



In words, if scroll down and not hidden, then hide. If scroll up and hidden, then unhide. But if scroll down and hidden, do nothing or scroll up and not hidden, do nothing.



How do you implement that with hooks?










share|improve this question


























    1















    const shouldHide = useHideOnScroll();
    return shouldHide ? null : <div>something</div>


    The useHideOnScroll behaviour should return updated value not on every scroll but only when there is a change.



    The pseudo logic being something like the following:



    if (scrolledDown && !isHidden) 
    setIsHidden(true);
    else if (scrolledUp && isHidden)
    setIsHidden(false);



    In words, if scroll down and not hidden, then hide. If scroll up and hidden, then unhide. But if scroll down and hidden, do nothing or scroll up and not hidden, do nothing.



    How do you implement that with hooks?










    share|improve this question
























      1












      1








      1








      const shouldHide = useHideOnScroll();
      return shouldHide ? null : <div>something</div>


      The useHideOnScroll behaviour should return updated value not on every scroll but only when there is a change.



      The pseudo logic being something like the following:



      if (scrolledDown && !isHidden) 
      setIsHidden(true);
      else if (scrolledUp && isHidden)
      setIsHidden(false);



      In words, if scroll down and not hidden, then hide. If scroll up and hidden, then unhide. But if scroll down and hidden, do nothing or scroll up and not hidden, do nothing.



      How do you implement that with hooks?










      share|improve this question














      const shouldHide = useHideOnScroll();
      return shouldHide ? null : <div>something</div>


      The useHideOnScroll behaviour should return updated value not on every scroll but only when there is a change.



      The pseudo logic being something like the following:



      if (scrolledDown && !isHidden) 
      setIsHidden(true);
      else if (scrolledUp && isHidden)
      setIsHidden(false);



      In words, if scroll down and not hidden, then hide. If scroll up and hidden, then unhide. But if scroll down and hidden, do nothing or scroll up and not hidden, do nothing.



      How do you implement that with hooks?







      reactjs state react-hooks






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked yesterday









      ZenVentziZenVentzi

      356413




      356413






















          3 Answers
          3






          active

          oldest

          votes


















          1














          You need to use window.addEventListener and https://reactjs.org/docs/hooks-custom.html guide.



          That is my working example:



          import React, useState, useEffect from "react";

          const useHideOnScrolled = () =>
          const [hidden, setHidden] = useState(false);

          const handleScroll = () =>
          const top = window.pageYOffset ;

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

          return hidden;
          ;

          export default useHideOnScrolled;


          live demo: https://codesandbox.io/s/w0p3xkoq2l?fontsize=14



          and i think name useIsScrolled() or something like that would be better






          share|improve this answer

























          • Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

            – ZenVentzi
            yesterday











          • You can check jayarjo's answer. While not 100% optimal, works as expected

            – ZenVentzi
            17 hours ago












          • @ZenVentzi oh, i get it. I'll try again then now and edit my answer

            – fard
            16 hours ago


















          1














          Here:



          const useHideOnScroll = () => 
          const prevScrollY = React.useRef<number>();
          const [isHidden, setIsHidden] = React.useState(false);

          React.useEffect(() =>
          const onScroll = () =>
          setIsHidden(isHidden =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          if (scrolledDown && !isHidden)
          return true;
          else if (!scrolledDown && isHidden)
          return false;
          else
          prevScrollY.current = window.scrollY;
          return isHidden;

          );
          ;

          console.log("adding listener");
          window.addEventListener("scroll", onScroll);
          return () =>
          window.removeEventListener("scroll", onScroll);
          ;
          , []);

          return isHidden;
          ;

          const Navbar = () =>
          const isHidden = useHideOnScroll();
          console.info("rerender");
          return isHidden ? null : <div className="navbar">navbar</div>;
          ;

          export default Navbar;


          You might have concern about setIsHidden causing rerender on every onScroll, by always returning some new state value, but a setter from useState is smart enough to update only if the value has actually changed.



          Also your .navbar (I've added a class to it) shouldn't change the layout when it appears or your snippet will get locked in an infinite loop. Here're appropriate styles for it as well:



          .navbar 
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          height: 30px;
          background: rgba(255, 255, 255, 0.8);



          Full CodeSandbox: https://codesandbox.io/s/13kr4xqrwq






          share|improve this answer

























          • Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

            – ZenVentzi
            19 hours ago












          • Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

            – ZenVentzi
            19 hours ago












          • Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

            – jayarjo
            18 hours ago


















          0














          After hours of dangling, here is what I came up with.



          const useHideOnScroll = () => 
          const [isHidden, setIsHidden] = useState(false);
          const prevScrollY = useRef<number>();

          useEffect(() =>
          const onScroll = () =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          const scrolledUp = !scrolledDown;

          if (scrolledDown && !isHidden)
          setIsHidden(true);
          else if (scrolledUp && isHidden)
          setIsHidden(false);


          prevScrollY.current = window.scrollY;
          ;

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

          return isHidden;
          ;


          Usage:



          const shouldHide = useHideOnScroll();
          return shouldHide ? null : <div>something</div>


          It's still suboptimal, because we reassign the onScroll when the isHidden changes. Everything else felt too hacky and undocumented. I'm really interested in finding a way to do the same, without reassigning onScroll. Comment if you know a way :)






          share|improve this answer























          • You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

            – fard
            17 hours ago










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55023041%2freact-hooks-how-to-implement-usehideonscroll-hook%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          You need to use window.addEventListener and https://reactjs.org/docs/hooks-custom.html guide.



          That is my working example:



          import React, useState, useEffect from "react";

          const useHideOnScrolled = () =>
          const [hidden, setHidden] = useState(false);

          const handleScroll = () =>
          const top = window.pageYOffset ;

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

          return hidden;
          ;

          export default useHideOnScrolled;


          live demo: https://codesandbox.io/s/w0p3xkoq2l?fontsize=14



          and i think name useIsScrolled() or something like that would be better






          share|improve this answer

























          • Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

            – ZenVentzi
            yesterday











          • You can check jayarjo's answer. While not 100% optimal, works as expected

            – ZenVentzi
            17 hours ago












          • @ZenVentzi oh, i get it. I'll try again then now and edit my answer

            – fard
            16 hours ago















          1














          You need to use window.addEventListener and https://reactjs.org/docs/hooks-custom.html guide.



          That is my working example:



          import React, useState, useEffect from "react";

          const useHideOnScrolled = () =>
          const [hidden, setHidden] = useState(false);

          const handleScroll = () =>
          const top = window.pageYOffset ;

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

          return hidden;
          ;

          export default useHideOnScrolled;


          live demo: https://codesandbox.io/s/w0p3xkoq2l?fontsize=14



          and i think name useIsScrolled() or something like that would be better






          share|improve this answer

























          • Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

            – ZenVentzi
            yesterday











          • You can check jayarjo's answer. While not 100% optimal, works as expected

            – ZenVentzi
            17 hours ago












          • @ZenVentzi oh, i get it. I'll try again then now and edit my answer

            – fard
            16 hours ago













          1












          1








          1







          You need to use window.addEventListener and https://reactjs.org/docs/hooks-custom.html guide.



          That is my working example:



          import React, useState, useEffect from "react";

          const useHideOnScrolled = () =>
          const [hidden, setHidden] = useState(false);

          const handleScroll = () =>
          const top = window.pageYOffset ;

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

          return hidden;
          ;

          export default useHideOnScrolled;


          live demo: https://codesandbox.io/s/w0p3xkoq2l?fontsize=14



          and i think name useIsScrolled() or something like that would be better






          share|improve this answer















          You need to use window.addEventListener and https://reactjs.org/docs/hooks-custom.html guide.



          That is my working example:



          import React, useState, useEffect from "react";

          const useHideOnScrolled = () =>
          const [hidden, setHidden] = useState(false);

          const handleScroll = () =>
          const top = window.pageYOffset ;

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

          return hidden;
          ;

          export default useHideOnScrolled;


          live demo: https://codesandbox.io/s/w0p3xkoq2l?fontsize=14



          and i think name useIsScrolled() or something like that would be better







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday

























          answered yesterday









          fardfard

          21411




          21411












          • Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

            – ZenVentzi
            yesterday











          • You can check jayarjo's answer. While not 100% optimal, works as expected

            – ZenVentzi
            17 hours ago












          • @ZenVentzi oh, i get it. I'll try again then now and edit my answer

            – fard
            16 hours ago

















          • Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

            – ZenVentzi
            yesterday











          • You can check jayarjo's answer. While not 100% optimal, works as expected

            – ZenVentzi
            17 hours ago












          • @ZenVentzi oh, i get it. I'll try again then now and edit my answer

            – fard
            16 hours ago
















          Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

          – ZenVentzi
          yesterday





          Appreciate the time taken to answer! I don't think that it's complete though. Your solution simply works only at the top of the page, which is not the goal. The goal is to work all the time, no matter how much the user has scrolled.

          – ZenVentzi
          yesterday













          You can check jayarjo's answer. While not 100% optimal, works as expected

          – ZenVentzi
          17 hours ago






          You can check jayarjo's answer. While not 100% optimal, works as expected

          – ZenVentzi
          17 hours ago














          @ZenVentzi oh, i get it. I'll try again then now and edit my answer

          – fard
          16 hours ago





          @ZenVentzi oh, i get it. I'll try again then now and edit my answer

          – fard
          16 hours ago













          1














          Here:



          const useHideOnScroll = () => 
          const prevScrollY = React.useRef<number>();
          const [isHidden, setIsHidden] = React.useState(false);

          React.useEffect(() =>
          const onScroll = () =>
          setIsHidden(isHidden =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          if (scrolledDown && !isHidden)
          return true;
          else if (!scrolledDown && isHidden)
          return false;
          else
          prevScrollY.current = window.scrollY;
          return isHidden;

          );
          ;

          console.log("adding listener");
          window.addEventListener("scroll", onScroll);
          return () =>
          window.removeEventListener("scroll", onScroll);
          ;
          , []);

          return isHidden;
          ;

          const Navbar = () =>
          const isHidden = useHideOnScroll();
          console.info("rerender");
          return isHidden ? null : <div className="navbar">navbar</div>;
          ;

          export default Navbar;


          You might have concern about setIsHidden causing rerender on every onScroll, by always returning some new state value, but a setter from useState is smart enough to update only if the value has actually changed.



          Also your .navbar (I've added a class to it) shouldn't change the layout when it appears or your snippet will get locked in an infinite loop. Here're appropriate styles for it as well:



          .navbar 
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          height: 30px;
          background: rgba(255, 255, 255, 0.8);



          Full CodeSandbox: https://codesandbox.io/s/13kr4xqrwq






          share|improve this answer

























          • Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

            – ZenVentzi
            19 hours ago












          • Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

            – ZenVentzi
            19 hours ago












          • Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

            – jayarjo
            18 hours ago















          1














          Here:



          const useHideOnScroll = () => 
          const prevScrollY = React.useRef<number>();
          const [isHidden, setIsHidden] = React.useState(false);

          React.useEffect(() =>
          const onScroll = () =>
          setIsHidden(isHidden =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          if (scrolledDown && !isHidden)
          return true;
          else if (!scrolledDown && isHidden)
          return false;
          else
          prevScrollY.current = window.scrollY;
          return isHidden;

          );
          ;

          console.log("adding listener");
          window.addEventListener("scroll", onScroll);
          return () =>
          window.removeEventListener("scroll", onScroll);
          ;
          , []);

          return isHidden;
          ;

          const Navbar = () =>
          const isHidden = useHideOnScroll();
          console.info("rerender");
          return isHidden ? null : <div className="navbar">navbar</div>;
          ;

          export default Navbar;


          You might have concern about setIsHidden causing rerender on every onScroll, by always returning some new state value, but a setter from useState is smart enough to update only if the value has actually changed.



          Also your .navbar (I've added a class to it) shouldn't change the layout when it appears or your snippet will get locked in an infinite loop. Here're appropriate styles for it as well:



          .navbar 
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          height: 30px;
          background: rgba(255, 255, 255, 0.8);



          Full CodeSandbox: https://codesandbox.io/s/13kr4xqrwq






          share|improve this answer

























          • Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

            – ZenVentzi
            19 hours ago












          • Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

            – ZenVentzi
            19 hours ago












          • Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

            – jayarjo
            18 hours ago













          1












          1








          1







          Here:



          const useHideOnScroll = () => 
          const prevScrollY = React.useRef<number>();
          const [isHidden, setIsHidden] = React.useState(false);

          React.useEffect(() =>
          const onScroll = () =>
          setIsHidden(isHidden =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          if (scrolledDown && !isHidden)
          return true;
          else if (!scrolledDown && isHidden)
          return false;
          else
          prevScrollY.current = window.scrollY;
          return isHidden;

          );
          ;

          console.log("adding listener");
          window.addEventListener("scroll", onScroll);
          return () =>
          window.removeEventListener("scroll", onScroll);
          ;
          , []);

          return isHidden;
          ;

          const Navbar = () =>
          const isHidden = useHideOnScroll();
          console.info("rerender");
          return isHidden ? null : <div className="navbar">navbar</div>;
          ;

          export default Navbar;


          You might have concern about setIsHidden causing rerender on every onScroll, by always returning some new state value, but a setter from useState is smart enough to update only if the value has actually changed.



          Also your .navbar (I've added a class to it) shouldn't change the layout when it appears or your snippet will get locked in an infinite loop. Here're appropriate styles for it as well:



          .navbar 
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          height: 30px;
          background: rgba(255, 255, 255, 0.8);



          Full CodeSandbox: https://codesandbox.io/s/13kr4xqrwq






          share|improve this answer















          Here:



          const useHideOnScroll = () => 
          const prevScrollY = React.useRef<number>();
          const [isHidden, setIsHidden] = React.useState(false);

          React.useEffect(() =>
          const onScroll = () =>
          setIsHidden(isHidden =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          if (scrolledDown && !isHidden)
          return true;
          else if (!scrolledDown && isHidden)
          return false;
          else
          prevScrollY.current = window.scrollY;
          return isHidden;

          );
          ;

          console.log("adding listener");
          window.addEventListener("scroll", onScroll);
          return () =>
          window.removeEventListener("scroll", onScroll);
          ;
          , []);

          return isHidden;
          ;

          const Navbar = () =>
          const isHidden = useHideOnScroll();
          console.info("rerender");
          return isHidden ? null : <div className="navbar">navbar</div>;
          ;

          export default Navbar;


          You might have concern about setIsHidden causing rerender on every onScroll, by always returning some new state value, but a setter from useState is smart enough to update only if the value has actually changed.



          Also your .navbar (I've added a class to it) shouldn't change the layout when it appears or your snippet will get locked in an infinite loop. Here're appropriate styles for it as well:



          .navbar 
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          height: 30px;
          background: rgba(255, 255, 255, 0.8);



          Full CodeSandbox: https://codesandbox.io/s/13kr4xqrwq







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 19 hours ago

























          answered 20 hours ago









          jayarjojayarjo

          6,356136297




          6,356136297












          • Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

            – ZenVentzi
            19 hours ago












          • Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

            – ZenVentzi
            19 hours ago












          • Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

            – jayarjo
            18 hours ago

















          • Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

            – ZenVentzi
            19 hours ago












          • Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

            – ZenVentzi
            19 hours ago












          • Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

            – jayarjo
            18 hours ago
















          Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

          – ZenVentzi
          19 hours ago






          Thank you. Just to clarify, in the else statement, where we simply return isHidden does it make the component re-render or not? My guess is not since it sees that state hasn't changed. Is that correct? This is absolutely not an issue, but I'm curious why the example code console.log('render') twice on state change?

          – ZenVentzi
          19 hours ago














          Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

          – ZenVentzi
          19 hours ago






          Replacing with console.info(`rerender $isHidden`); we get output such as rerender true rerender true rerender false rerender false instead of just once. Why is that? Again, this is not an issue but I'm trying to make sense of it all

          – ZenVentzi
          19 hours ago














          Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

          – jayarjo
          18 hours ago





          Double thing is kind of mystery for me at the moment. I will read the source when I have spare time to see what is actually happening. At the moment you can debounce the onScroll handler (since it fires multiple times and I guess that's not desirable anyway).

          – jayarjo
          18 hours ago











          0














          After hours of dangling, here is what I came up with.



          const useHideOnScroll = () => 
          const [isHidden, setIsHidden] = useState(false);
          const prevScrollY = useRef<number>();

          useEffect(() =>
          const onScroll = () =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          const scrolledUp = !scrolledDown;

          if (scrolledDown && !isHidden)
          setIsHidden(true);
          else if (scrolledUp && isHidden)
          setIsHidden(false);


          prevScrollY.current = window.scrollY;
          ;

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

          return isHidden;
          ;


          Usage:



          const shouldHide = useHideOnScroll();
          return shouldHide ? null : <div>something</div>


          It's still suboptimal, because we reassign the onScroll when the isHidden changes. Everything else felt too hacky and undocumented. I'm really interested in finding a way to do the same, without reassigning onScroll. Comment if you know a way :)






          share|improve this answer























          • You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

            – fard
            17 hours ago















          0














          After hours of dangling, here is what I came up with.



          const useHideOnScroll = () => 
          const [isHidden, setIsHidden] = useState(false);
          const prevScrollY = useRef<number>();

          useEffect(() =>
          const onScroll = () =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          const scrolledUp = !scrolledDown;

          if (scrolledDown && !isHidden)
          setIsHidden(true);
          else if (scrolledUp && isHidden)
          setIsHidden(false);


          prevScrollY.current = window.scrollY;
          ;

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

          return isHidden;
          ;


          Usage:



          const shouldHide = useHideOnScroll();
          return shouldHide ? null : <div>something</div>


          It's still suboptimal, because we reassign the onScroll when the isHidden changes. Everything else felt too hacky and undocumented. I'm really interested in finding a way to do the same, without reassigning onScroll. Comment if you know a way :)






          share|improve this answer























          • You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

            – fard
            17 hours ago













          0












          0








          0







          After hours of dangling, here is what I came up with.



          const useHideOnScroll = () => 
          const [isHidden, setIsHidden] = useState(false);
          const prevScrollY = useRef<number>();

          useEffect(() =>
          const onScroll = () =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          const scrolledUp = !scrolledDown;

          if (scrolledDown && !isHidden)
          setIsHidden(true);
          else if (scrolledUp && isHidden)
          setIsHidden(false);


          prevScrollY.current = window.scrollY;
          ;

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

          return isHidden;
          ;


          Usage:



          const shouldHide = useHideOnScroll();
          return shouldHide ? null : <div>something</div>


          It's still suboptimal, because we reassign the onScroll when the isHidden changes. Everything else felt too hacky and undocumented. I'm really interested in finding a way to do the same, without reassigning onScroll. Comment if you know a way :)






          share|improve this answer













          After hours of dangling, here is what I came up with.



          const useHideOnScroll = () => 
          const [isHidden, setIsHidden] = useState(false);
          const prevScrollY = useRef<number>();

          useEffect(() =>
          const onScroll = () =>
          const scrolledDown = window.scrollY > prevScrollY.current!;
          const scrolledUp = !scrolledDown;

          if (scrolledDown && !isHidden)
          setIsHidden(true);
          else if (scrolledUp && isHidden)
          setIsHidden(false);


          prevScrollY.current = window.scrollY;
          ;

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

          return isHidden;
          ;


          Usage:



          const shouldHide = useHideOnScroll();
          return shouldHide ? null : <div>something</div>


          It's still suboptimal, because we reassign the onScroll when the isHidden changes. Everything else felt too hacky and undocumented. I'm really interested in finding a way to do the same, without reassigning onScroll. Comment if you know a way :)







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 21 hours ago









          ZenVentziZenVentzi

          356413




          356413












          • You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

            – fard
            17 hours ago

















          • You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

            – fard
            17 hours ago
















          You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

          – fard
          17 hours ago





          You can move onScroll up with isHidden as parameter so you wont have to reassign it every time

          – fard
          17 hours ago

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55023041%2freact-hooks-how-to-implement-usehideonscroll-hook%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          How to get text form Clipboard with JavaScript in Firefox 56?How to validate an email address in JavaScript?How do JavaScript closures work?How do I remove a property from a JavaScript object?How do you get a timestamp in JavaScript?How do I copy to the clipboard in JavaScript?How do I include a JavaScript file in another JavaScript file?Get the current URL with JavaScript?How to replace all occurrences of a string in JavaScriptHow to check whether a string contains a substring in JavaScript?How do I remove a particular element from an array in JavaScript?

          Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme

          Thal And Out Agency railway station See also References External links Navigation menuOfficial Web Site of Pakistan RailwaysArchivedOfficial Web Site of Pakistan Railwayseeexpanding ite