Optimize Your  E-commerce Website's User Experience with ReactJS Scroll Restoration Implementation

Optimize Your E-commerce Website's User Experience with ReactJS Scroll Restoration Implementation

ยท

6 min read

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">
                                          &euro; {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">
                    &euro; {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.

Did you find this article valuable?

Support Chukwuka Reuben by becoming a sponsor. Any amount is appreciated!

ย