6

I have this list of products on a ReactJS store:

{productsList.map((product) => (
  <ProductItem
    product={product}
  />
)}

When I add more products in this list, the scroll position goes to the end of the list. The code to add more products:

function nextPage() {
  getMoreProducts().then((newProducts)=> {
    setProductsList(productsList.concat(newProducts))
  })
}

I need to keep the scroll position, because this way the user have to scroll to top to see the loaded new products.

I have try storing the scroll position, but the changes are done before the list grow, so nothing happens:

function nextPage() {
  const actualScrollPosition = window.pageYOffset
  getMoreProducts().then((newProducts)=> {
    setProductsList(productsList.concat(newProducts))       //<- setState from React is async.
    window.scroll({ top: actualScrollPosition, behavior: "smooth" });
  })    
}
Danilo Cunha
  • 1,048
  • 2
  • 13
  • 22

2 Answers2

4

Try setting the scroll position in a useLayoutEffect triggered by the change to productsList:

import React from 'react'

type Product = {
  name: string
}

const getMoreProducts = async () => ([{name:'foo'}])

export const ProductItem: React.FC<{ product: Product> = ({ product }) => {
  return <div>{product.name}</div>
}

export const ProductList: React.FC = () => {
  const [productsList, setProductsList] = React.useState([])

  let pageYOffset = window.pageYOffset

  function nextPage() {
    getMoreProducts().then((newProducts)=> {
      pageYOffset = window.pageYOffset
      setProductsList(productsList.concat(newProducts))
    })    
  }

  React.useLayoutEffect(() => {
    window.scroll({ top: pageYOffset });
  }, [productsList])

  return (
    <>
      {productsList.map((product) => (
        <ProductItem
          product={product}
        />
      ))}
      <button onClick={nextPage}>Load more</button>
    </>
  )
}

In this case, you also don't want the behavior: "smooth".

Patrick Fisher
  • 7,926
  • 5
  • 35
  • 28
0

What you can do is save the const savedHeight = document.body.offsetHeight value which is the full document height. Then after the products have loaded, set window.scrollTo(0, savedHeight) since body seem to be in charge for the scrolling on your page. This will make the screen stay at the same place as when the load button was clicked.

Gabriel Petersson
  • 8,434
  • 4
  • 32
  • 41
  • Sorry just tested on your site and it did not work with scrollTop, instead you can use scrollTo on window to scroll. Tested it out and work perfect! – Gabriel Petersson Sep 01 '20 at 20:15