Hello everyone, it’s me again. Today I would like to share with you a feature that when going to work will be able to meet, this feature I have just discovered, on google there are quite a lot of articles about it, but for these few posts I will myself code and hope to help you.
Did you notice when shoppe looking for a certain product it will have a long list of many sp, when you scroll down and click on any sp, then back it up, it still remains at the position that I scrolled before that? Here I will proceed to make an example so that you can imagine it more easily, please follow me:
1. Create a project:
First, run this command to initialize a project using create-react-app :
1 2 | npx create-react-app keep-scroll-postion |
Once created, run it with the command below to check if your project has run yet:
1 2 | yarn start or npm start |
2. Install React router:
To use React router, you need to install react-router-dom package for yourself:
1 2 | yarn add react-router-dom |
3. Create files:
After the installation is complete you proceed to create two more pages for yourself in Home.js and Product.js in ./src In the Home.js and Product.js files, I will give the same difference only in the component name:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import { useKeepPositionScroll } from './hooks'; export default function Home() { // đổi tên thành Product (trong file Product.js) const items = Array.from(new Array(20), (_, i) => i); useKeepPositionScroll(); return ( <> <h1>Home</h1> // đây cũng vậy <section> {items.map((item, index) => ( <div key={index} className="item"> {item} </div> ))} </section> </> ); } |
Let me explain a little more about the above code, you can see that I am importing useKeepPositionScroll (I will explain about this guy). Here I want to create a list with 20 items so I created with Array.from(new Array(20), (_, i) => i);
Then use map to show it.
Next, I will proceed to create a menu to click to switch pages. First create components / Navbar / index.js with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 | import { Link } from 'react-router-dom'; export default function Navbar() { return ( <nav> <Link to="/">HOME</Link> <Link to="/about">ABOUT</Link> <Link to="/products">PRODUCTS</Link> </nav> ) } |
The above code is also simple so I do not explain more.
Then go to the App.js file to let me configure the router.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import Navbar from './components/Navbar'; import About from './About'; import Home from './Home'; import Products from './Products'; import './App.css'; function App() { return ( <main className="App"> <Router> <Navbar /> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/products" component={Products} /> </Switch> </Router> </main> ); } export default App; |
If you are not familiar with React router, you can read more here , easy to understand
Then run it to see if it is ok!
Then finally is the custom hook useKeepPositionScroll.js , you create yourself /hooks/index.js with the code:
1 2 | export { default as useKeepPositionScroll } from './useKeepPositionScroll'; |
Then create /hooks/useKeepPositionScroll.js :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | import { useState, useEffect } from "react"; import { useLocation } from "react-router-dom"; export default function useKeepPositionScroll() { let location = useLocation(); const [scrollTop, setScrollTop] = useState(0); const [isScroll, setIsScroll] = useState(false); useEffect(() => { let newScrollPosition = []; // get scrollPosition from sessionStorage const scrollPosition = JSON.parse(sessionStorage.getItem("scroll-position")) || []; // get index const id = scrollPosition.findIndex( (v) => v.pathname === location.pathname ); // check if pathname exist in storage if (id !== -1) { // if not scroll then default scroll to position available in storage if (!isScroll) window.scrollTo(0, scrollPosition[id].position); // update sessionStorage newScrollPosition = [...scrollPosition]; newScrollPosition.splice(id, 1, { pathname: location.pathname, position: scrollTop, }); sessionStorage.setItem( "scroll-position", JSON.stringify(newScrollPosition) ); return; } newScrollPosition = [ ...scrollPosition, { pathname: location.pathname, position: 0, }, ]; sessionStorage.setItem( "scroll-position", JSON.stringify(newScrollPosition) ); window.scrollTo(0, 0); }, [scrollTop, location.pathname, isScroll]); // Get scroll top const windowScrollTop = () => { const position = window.pageYOffset; setIsScroll(true); setScrollTop(position); }; useEffect(() => { window.addEventListener("scroll", windowScrollTop); return () => window.removeEventListener("scroll", windowScrollTop); }, []); return location; } |
The above code is that I am creating a custom hook, this file has the function of checking if the pathname of this page already exists in sessionStorage, if not, add it, but then it will be replaced with another value. Its structure means like this:
1 2 | [{"pathname":"/","position":300},{"pathname":"/about","position":0},{"pathname":"/products","position":0}] |
In the above code, I have noted cmt so the readers will understand.
4. Conclusion:
It’s all over, hope it will be helpful for you guys, have a nice weekend, thanks all