Get scroll position with Reactjs

Viewed 159188

I use reactjs and want to handle scroll with click event.

Firstly, I rendered list of posts with componentDidMount.

Secondly, by click event on each post in list, It will display post detail and scroll to top (because I put post detail to top position of page).

Thirdly, by clicking "close button" in post detail, it will return previous list of posts but I want website will scroll to exactly to position of clicked post.

I use like this:

Click event to view post detail:

inSingle = (post, e) => {
   this.setState({
        post: post,
        theposition: //How to get it here?
   });
   window.scrollTo(0, 0);
}

I want to get state of theposition then I can do scroll exactly to position of clicked post by 'Close event'.

10 Answers

You can use event listener in react like you will use in other js framework or library.

componentDidMount() {
  window.addEventListener('scroll', this.listenToScroll)
}

componentWillUnmount() {
  window.removeEventListener('scroll', this.listenToScroll)
}

listenToScroll = () => {
  const winScroll =
    document.body.scrollTop || document.documentElement.scrollTop

  const height =
    document.documentElement.scrollHeight -
    document.documentElement.clientHeight

  const scrolled = winScroll / height

  this.setState({
    theposition: scrolled,
  })
}

In case you need to keep on track of the scroll position, you can use react hooks to do so, that way it's possible to check the scroll position any time you need it:

import React, { useState, useEffect } from 'react';

...
// inside component:

const [scrollPosition, setScrollPosition] = useState(0);
const handleScroll = () => {
    const position = window.pageYOffset;
    setScrollPosition(position);
};

useEffect(() => {
    window.addEventListener('scroll', handleScroll, { passive: true });

    return () => {
        window.removeEventListener('scroll', handleScroll);
    };
}, []);

In this case useEffect will behavior similar to componentDidMount, it will fire once the component has rendered, but also in every render, as Jared Beach commented bellow: "window.addEventListener is smart enough to discard subsequent calls with the same parameters". . Make sure to return the cleanup function, similar to what you'd do in componentWillUnmount.

This should work:

this.setState({
    post: post,
    theposition: window.pageYOffset
});
import React, { useLayoutEffect, useState } from 'react';

export default function useWindowPosition() {
  const [scrollPosition, setPosition] = useState(0);
  useLayoutEffect(() => {
    function updatePosition() {
      setPosition(window.pageYOffset);
    }
    window.addEventListener('scroll', updatePosition);
    updatePosition();
    return () => window.removeEventListener('scroll', updatePosition);
  }, []);
  return scrollPosition;
}

Combining some of the other answers, this is exactly what is needed here. Simply use this hook to get the scrollX (horizontal) and scrollY (vertical) positions from the window. It'll be updated as the user scrolls.

/// in useWindowScrollPositions.js

import { useEffect, useState } from 'react'

export const useWindowScrollPositions = () => {

   const [scrollPosition, setPosition] = useState({ scrollX: 0, scrollY: 0 })

   useEffect(() => {
    function updatePosition() {
        setPosition({ scrollX: window.scrollX, scrollY: window.scrollY })
    }

    window.addEventListener('scroll', updatePosition)
    updatePosition()

    return () => window.removeEventListener('scroll', updatePosition)
   }, [])

   return scrollPosition
}

Then call the hook in your function component:

/// in MyComponent.jsx

import { useWindowScrollPositions } from 'path/to/useWindowScrollPositions'

export const MyComponent = () => {
   const { scrollX, scrollY } = useWindowScrollPositions()
   
   return <div>Scroll position is ({scrollX}, {scrollY})</div>
} 

Note that window.pageXOffset and window.pageYOffset, which were used in the other answers from years ago, have been deprecated in favor of window.scrollX and window.scrollY

Like this:

theposition: e.y // or, e.pageY

Or,

theposition: e.clientY - e.currentTarget.getBoundingClientRect().top

You can use the native react event listener.

<div onScroll={(e) => console.log("scrolling!", e.target.scrollTop)}>
    <h3>Some huge div</h3>
</div>

to get current scroll position you can use

horizontal scrolling amount window.pageXOffset

vertical scrolling amount window.pageYOffset

Found this on MDN:

element.scrollHeight - Math.abs(element.scrollTop) === element.clientHeight

this repo helped me a lot https://github.com/n8tb1t/use-scroll-position

yarn add @n8tb1t/use-scroll-position

import { useScrollPosition } from '@n8tb1t/use-scroll-position'


useScrollPosition(({ prevPos, currPos }) => {
 console.log(currPos.x)
 console.log(currPos.y)
})
Related