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
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
add a comment |
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
add a comment |
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
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
reactjs state react-hooks
asked yesterday
ZenVentziZenVentzi
356413
356413
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
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
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
add a comment |
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
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 codeconsole.log('render')twice on state change?
– ZenVentzi
19 hours ago
Replacing withconsole.info(`rerender $isHidden`);we get output such asrerender true rerender true rerender false rerender falseinstead 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 theonScrollhandler (since it fires multiple times and I guess that's not desirable anyway).
– jayarjo
18 hours ago
add a comment |
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 :)
You can move onScroll up with isHidden as parameter so you wont have to reassign it every time
– fard
17 hours ago
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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
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 codeconsole.log('render')twice on state change?
– ZenVentzi
19 hours ago
Replacing withconsole.info(`rerender $isHidden`);we get output such asrerender true rerender true rerender false rerender falseinstead 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 theonScrollhandler (since it fires multiple times and I guess that's not desirable anyway).
– jayarjo
18 hours ago
add a comment |
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
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 codeconsole.log('render')twice on state change?
– ZenVentzi
19 hours ago
Replacing withconsole.info(`rerender $isHidden`);we get output such asrerender true rerender true rerender false rerender falseinstead 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 theonScrollhandler (since it fires multiple times and I guess that's not desirable anyway).
– jayarjo
18 hours ago
add a comment |
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
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
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 codeconsole.log('render')twice on state change?
– ZenVentzi
19 hours ago
Replacing withconsole.info(`rerender $isHidden`);we get output such asrerender true rerender true rerender false rerender falseinstead 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 theonScrollhandler (since it fires multiple times and I guess that's not desirable anyway).
– jayarjo
18 hours ago
add a comment |
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 codeconsole.log('render')twice on state change?
– ZenVentzi
19 hours ago
Replacing withconsole.info(`rerender $isHidden`);we get output such asrerender true rerender true rerender false rerender falseinstead 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 theonScrollhandler (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
add a comment |
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 :)
You can move onScroll up with isHidden as parameter so you wont have to reassign it every time
– fard
17 hours ago
add a comment |
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 :)
You can move onScroll up with isHidden as parameter so you wont have to reassign it every time
– fard
17 hours ago
add a comment |
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 :)
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 :)
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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