useScrollPosition

Medium

Prompt

Create a custom React hook called useScrollPosition that tracks the window's scroll position on both the X and Y axes.

Requirements

  • The hook should return an object with the following properties:
    • x: The current horizontal scroll position (scrollX)
    • y: The current vertical scroll position (scrollY)
  • The hook should update the scroll position whenever the user scrolls

Example

function ScrollTracker() {
const { x, y } = useScrollPosition();

return (
<div>
{x} {y}
</div>
);
}

Playground

Hint 1

Start by creating a state variable with useState to store the scroll position as an object with x and y properties.

Hint 2

Use the useEffect hook to add an event listener for the 'scroll' event on the window object.

Hint 3

Remember to remove the event listener in the cleanup function returned by useEffect to prevent memory leaks.

Solution

Explanation

Our useScrollPosition hook is quite straightforward! Let's see how it works:

First, we create a state variable to keep track of both X and Y scroll positions:

const [scrollPosition, setScrollPosition] = useState({
x: 0,
y: 0,
});

Next, we use useEffect to set up an event listener for scrolling:

useEffect(() => {
function handleScroll() {
setScrollPosition({
x: Math.round(window.scrollX),
y: Math.round(window.scrollY),
});
}

window.addEventListener('scroll', handleScroll);

// Clean up the event listener when the component unmounts
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);

This useEffect does a few key things:

  1. Creates a handleScroll function that updates our state with the current scroll position
  2. Adds it as an event listener to the window's 'scroll' event
  3. Returns a cleanup function that removes the event listener when the component unmounts

We use an empty dependency array ([]) to ensure our effect only runs once when the component mounts.

Finally, we return the scroll position object so components using our hook can access it:

return scrollPosition;

That's it! This hook is a great example of how React's built-in hooks can be combined to create reusable pieces of functionality.

Why do we use Math.round() for the scroll values? Browsers return fractional pixel values for scroll positions (like 100.33333px).

00:00