Optimize Your E-commerce Website's User Experience with ReactJS Scroll Restoration Implementation
User experience can be the overall experience of a person using a product, such as a website or an application, in terms of how pleasing or easy it is to use.
For e-commerce websites, a good user experience is essential because it helps with conversion, turning visitors into customers, and customer retention, which results in repeat purchases, customer loyalty, website recommendations to others, positive reviews, and other outcomes. The benefits of a good user experience are numerous; the ones mentioned above are only a few.
This is what you will learn in this article:
Scroll Restoration and how it can boost your website's user experience.
How to store data in the browser's localStorage.
How to implement Scroll Restoration on your e-commerce website.
What is Scroll Restoration?
Scroll Restoration is simply the ability of the browser to preserve the scroll position of a web page after the user leaves the page and wants to navigate back.
Imagine users having to scroll through a page repeatedly to find their previous position or users getting lost or disoriented on your e-commerce site because they have been scrolling for a while. This might annoy the user, take up time, and may result in the majority of your product not being discovered by the user, especially if your e-commerce site displays a large number of products.
The "Scroll Restoration" feature, a little but notable feature, allows you to resolve all the aforementioned problems.
Let's consider the following situation:
You visit an e-commerce website that has a product listing page that looks somewhat like this:
And then, as you scroll down to browse through the list looking for specific items, you find an item of interest and click on it to view more details.
As soon as you click, you are taken to the product details page, where you can see detailed information about the selected product. looking something like this:
After reviewing the information, you decide to return to the product listing page. Your scroll position is automatically restored to where you left off, saving you the trouble of having to scroll back down the product list.
Scroll Restoration is responsible for this functionality.
Assumptions and Prerequisites
For you to comprehend and be able to follow this lesson, I will be assuming that you already have a basic understanding of some topics and that you have some things in place. I'll be listing them out in this section of the article because that is its purpose:
Prerequisites
Familiarity with Reactjs and its ecosystem
Familiarity with React-Router for handling routing in your application
Assumptions
You already have your e-commerce storefront built with Reactjs
A page that displays a list of products has already been implemented. Your product list code may resemble this, as this is the code we will be working with in this article:
//ProductList.jsx import { UseEffect, UseState, useEffect, useState } from "react"; import { Link } from "react-router-dom"; import { medusaClient } from "../utils/client.js"; function ProductList() { const [products, setProducts] = useState([]); useEffect(() => { const fetchProducts = async () => { const res = await medusaClient.products.list(); setProducts(res.products); }; fetchProducts(); }, []); return ( <> <section className="mt-8 lg:px-16 xs:px-6"> <h2 className="text-center mb-12 mt-8 text-2xl">Featured Products</h2> <div className="mx-8"> <div className="grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-1 gap-8"> {products.map((productItem) => { return ( <div className="p-2" style={{ backgroundColor: "rgb(231, 231, 231)", height: "350px", }} > <div style={{ height: "12rem" }}> <img className="h-48 w-full" style={{ objectFit: "cover" }} src={productItem?.thumbnail} alt="product image" /> </div> <p className="text-center py-4 font-semibold"> {productItem?.title} </p> <p className="text-center"> € {productItem?.variants[0].prices[0].amount / 100} </p> <div className="text-center"> <Link className="underline" to={`/products/${productItem?.id}`} > See product </Link> </div> </div> ); })} </div> </div> </section> </> ); } export default ProductList;
You have also implemented a single-product page that shows detailed information about a specific product.
Implementing the Scroll Restoration
In this section, we will delve into the implementation of scroll restoration:
We are going to start by defining a function called handleScroll
that will take an id
parameter:
const handleScroll = (id) => {
}
Next, using the setItem
method from the localStorage, we will store the id
in the browser's localStorage under the key "myId".
const handleClick = (id) => {
localStorage.setItem("myId", JSON.stringify(id));
};
Next, navigate to the link with "see product" and call handleSrcoll
function with the id
parameter when the link is clicked:
<Link
className="underline"
to={`/products/${productItem?.id}`}
onClick={() => handleClick(id)}
>
See product
</Link>;
Explanation of what is going on in the above snippet: whenever a user clicks "see product" to get to the product's details page. Using the handleClick function, we immediately note the product's id that was clicked and save it in the browser's local storage.
When the user returns to the product list page, we fetch the id we saved in our localStorage under the value "myId." The following code snippet will accomplish the trick:
const getId = ()=> {
let myId = localStorage.getItem('myId');
if(myId){
return (
myId = JSON.parse(localStorage.getItem('myId'))
)
} else {
return(null)
}
}
The getId
function will be called when the component is initialized, and its returned value will be used as the initial value for the idToScrollTo
state variable. Like this :
const [idToScrollTo, setIdToScrollTo] = useState(getId);
Now this is the most important part of the article; anytime a user returns to our website, we should hold off on resuming page scrolling until the product list has been obtained. To accomplish this, the scrollIntoView would be delayed by one second:
useEffect(() => {
const fetchProducts = async () => {
const res = await medusaClient.products.list();
setProducts(res.products);
};
fetchProducts();
setTimeout(() => {
const element = document.getElementById(idToScrollTo);
console.log(element)
element.scrollIntoView();
}, 1000);
},[]);
Next, whenever the product has scrolled into view, we want to remove the key "myId" from the localStorage. A condition that verifies that the value of idToScrollTo is not null would also need to be written. For a revised version of the preceding snippet, see the following code:
useEffect(() => {
const fetchProducts = async () => {
const res = await medusaClient.products.list();
setProducts(res.products);
};
fetchProducts();
setTimeout(() => {
if(idToScrollTo !== null){
const element = document.getElementById(idToScrollTo);
console.log(element)
element.scrollIntoView();
localStorage.removeItem('myId');
}
}, 1000);
},[]);
With this, your scroll restoration should work fine now. Check the next section for the complete code.
Complete Code
ProductList.jsx
//ProductList.jsx
import { UseEffect, UseState, useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { medusaClient } from "../utils/client.js";
const getId = () => {
let myId = localStorage.getItem("myId");
if (myId) {
return (myId = JSON.parse(localStorage.getItem("myId")));
} else {
return null;
}
};
function ProductList() {
const [products, setProducts] = useState([]);
const [idToScrollTo, setIdToScrollTo] = useState(getId);
const handleClick = (id) => {
localStorage.setItem("myId", JSON.stringify(id));
};
useEffect(() => {
const fetchProducts = async () => {
const res = await medusaClient.products.list();
setProducts(res.products);
};
fetchProducts();
setTimeout(() => {
if (idToScrollTo !== null) {
const element = document.getElementById(idToScrollTo);
console.log(element);
element.scrollIntoView();
localStorage.removeItem("myId");
}
}, 1000);
}, []);
return (
<>
<section className="mt-8 lg:px-16 xs:px-6">
<h2 className="text-center mb-12 mt-8 text-2xl">Featured Products</h2>
<div className="mx-8">
<div className="grid lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-1 gap-8">
{products.map((productItem) => {
return (
<div
id={productItem.id}
className="p-2"
style={{
backgroundColor: "rgb(231, 231, 231)",
height: "350px",
}}
>
<div style={{ height: "12rem" }}>
<img
className="h-48 w-full"
style={{ objectFit: "cover" }}
src={productItem?.thumbnail}
alt="product image"
/>
</div>
<p className="text-center py-4 font-semibold">
{productItem?.title}
</p>
<p className="text-center">
€ {productItem?.variants[0].prices[0].amount / 100}
</p>
<div
className="text-center"
onClick={() => handleClick(productItem.id)}
>
<Link
className="underline"
to={`/products/${productItem?.id}`}
>
See product
</Link>
</div>
</div>
);
})}
</div>
</div>
</section>
</>
);
}
export default ProductList;
Conclusion
In this article, I've covered how a good user experience on your e-commerce website may help your business, attract good reviews, and drive sales. Additionally, I explained Scroll restoration and demonstrated how to use it to improve user experience on your website significantly. Finally, I showed you how to implement it.