Issue
This is alot of code but it is the minimal way that I could think of reproducing my problem.
view in sandbox: https://codesandbox.io/s/silly-kare-j0kmz
I would like the header bar to hide upon scrolling. The problem is everytime I click on a box to go to another route, or click header to come back to the home route, the scroll bar stays where it was before. That is everytime I move from route to route, the scrollbar does not move to the top.
I was able to fix this problem with the scrollToTop code, But in order to make it scroll to the top, I need to remove "overflow-y" from App.css, which stops my header from reacting onScroll.
I came to realize this is because window is perhaps a BOM object and only targets the browser window itself, not div class which I have assigned onScroll to.
So it seems I can do either OR, but not both functions together. I would like both to happen, The scrolToTop on location change AND to keeep the Header Reacting to the onScroll method. How can I do that?
App.js ---------------------------------------------------
Provides routing to First.js and Second.js. Also has the onScroll method. That is when you scroll up, the header appears, and when you scroll up the header disapears. Along with some routing to 2 simple components.
import './App.css';
import {useState, useEffect, useRef} from 'react';
import { Route, Routes} from 'react-router-dom';
import Second from "./Second/Second";
import First from "./First/First";
import Header from './Header/Header';
import ScrollToTop from './ScrollToTop/ScrollToTop'
function App() {
const prevScrollY = useRef(0);
const [goingUp, setGoingUp] = useState(true);
const [HeaderisVisible, setHeaderIsVisible] = useState(0);
const onScroll = (e) => {
const currentScrollY = e.target.scrollTop;
if (prevScrollY.current < currentScrollY && goingUp) {
setGoingUp(false);
}
if (prevScrollY.current > currentScrollY && !goingUp) {
setGoingUp(true);
}
prevScrollY.current = currentScrollY;
console.log(goingUp, currentScrollY);
};
return (
<div className="App" onScroll = {onScroll}>
<ScrollToTop/>
<Routes>
<Route path = '/' exact element = {<First GoingUp = {goingUp}/>}/>
<Route path = '/second' element = {<Second GoingUp = {goingUp}/>} />
<Route path = '*'>
NOT FOUND
</Route>
</Routes>
</div>
);
}
export default App;
Header.js -------------------------------------------------
Header takes props from the state initialized in App.js containing a true or flase variable. and uses that in a conditional to either show or hide the header. Also on clicking the header you go back to the home page.
import './Header.css';
import {useState, useEffect} from 'react';
import {Link} from 'react-router-dom';
function Header(props) {
const [HeaderisVisible, setHeaderIsVisible] = useState(0);
useEffect(() => {
if(props.GoingUp == true){
setHeaderIsVisible(0);
}else{
setHeaderIsVisible(-199);
}
}, [props.GoingUp]);
return (
<Link to = '/'><div className = "Header"
style = {{
top: `${HeaderisVisible}px`
}}>
</div> </Link>
);
}
export default Header;
First.js --------------------------------------------------
First is a simple component that just displays some divs. Each black div will route the the second page.
import './First.css';
import {Link} from 'react-router-dom';
import Header from '../Header/Header';
function First(props) {
return (
<div className="First">
<Header GoingUp = {props.GoingUp}/>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
</div>
);
}
export default First;
Second.js -------------------------------------------------
Second is a simple component that just displays some red divs.
import './Second.css';
import { Route, Routes, Link} from 'react-router-dom';
import Header from '../Header/Header';
function Second(props) {
return (
<div className="Second">
<Header GoingUp = {props.GoingUp}/>
<div className = "entity2"></div>
<div className = "entity2"></div>
<div className = "entity2"></div>
<div className = "entity2"></div>
<div className = "entity2"></div>
</div>
);
}
export default Second;
ScrollToTop.js --------------------------------------------
Gets the location via the url search path, and scrolls to the top of the page on every search.
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop(props) {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
First.css
-----------------------------------
.entity{
height: 200px;
margin: auto;
width: 200px;
border: 2px solid black;
background-color: black;
margin-top: 200px;
}
Second.css
-------------------------------------
.Second{
background-color: lightgreen;
}
.entity2{
height: 200px;
margin: auto;
width: 200px;
border: 2px solid black;
background-color: red;
margin-top: 200px;
}
Header.css
------------------------------------
.Header{
background-color: brown;
height: 200px;
position: fixed;
width: calc(100% - 17px);
}
App.css
-------------------------------------
html{
margin: 0;
}
body{
margin: 0;
}
.App{
overflow-y: auto;
background-color: lightblue;
height: 100vh;
}
Solution
I was able to solve my problem by replacing window.scrollTo(...) with the following: props.refProp.current.scrollTop = 0; inside of scrollToTop function.
export default function ScrollToTop(props) {
const { pathname } = useLocation();
useEffect(() => {
props.refProp.current.scrollTop = 0;
}, [pathname]);
return null;
}
Answered By - chree
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.