How to Use the Page Visibility API and Custom React Hooks to Improve User Experience
Learn how to enhance user experience with the Page Visibility API and custom React hooks.
As modern browsers support tabbed browsing, webpages might remain in the background, hidden from users. The Page Visibility API offers insights into whether a webpage is visible or not, making it a valuable resource for developers. In this article, we will comprehensively discuss the Page Visibility API, and its use cases, and demonstrate how to create a custom React Hook for more efficient usage.
Visibility Change Event
When a user minimizes the window or switches to another tab, the Page Visibility API sends a visibilitychange
event to inform listeners about the change in the page's state. We can handle this event and perform actions based on the visibility state, such as pausing a video when the page is hidden from view.
Using the Page Visibility API
The Page Visibility API is part of the document object. We can use it by checking the document.hidden
property(described as “historical”) or the document.visibilityState
property(recommend), both of which are read-only. To monitor changes in both properties, we can listen to the visibilitychange
event.
Example: Pausing a Video
In this example, we will pause a video when switching to a different tab. First, we add the HTML code for the video:
<video id="myVideo" width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
Your browser does not support the video tag.
</video>
Next, in our JavaScript code, we listen to the visibilitychange
event:
document.addEventListener("visibilitychange", function() {
const video = document.getElementById("myVideo");
if (document.visibilityState === "hidden") {
video.pause();
} else if (document.visibilityState === "visible") {
video.play();
}
});
In our event listener callback, we pause the video when the visibilityState
is not 'visible'
. This means the user cannot see the tab either because they navigated away, minimized the window, or turned the screen off. Alternatively, you can set the event handler to the onvisibilitychange
property of document
.
document.visibilityState
can take on these values:
visible
: The page is visible to the user as a foreground tabhidden
: The page is not visible to the user, either because it's in the background, minimized, or the device's screen is off
Creating a Custom React Hook
Now that we have covered the Page Visibility API basics, let’s create a custom React Hook to make it even more convenient to use within a React application.
Creating the usePageVisibility
Hook
First, let’s create a new usePageVisibility
Hook that utilizes the useState
and useEffect
Hooks to manage the page visibility state:
import { useState, useEffect } from 'react';
function usePageVisibility() {
const [isVisible, setIsVisible] = useState(!document.hidden);
useEffect(() => {
function handleVisibilityChange() {
setIsVisible(document.visibilityState === 'visible');
}
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
return isVisible;
}
This custom Hook returns a boolean value representing the visibility of the page. It sets up an event listener for the visibilitychange
event and updates the isVisible
state accordingly.
What if you could reuse this custom hook across projects with a simple
npm i @bit/your-username/use-page-visibility
? You could do just that using an open-source toolchain like Bit.
Find out more:
Usage Example
Now, let’s see how we can use our custom usePageVisibility
Hook in a React component to pause and play a video:
import { useRef, useEffect } from 'react';
import usePageVisibility from './usePageVisibility';
function VideoPlayer({ src }) {
const videoRef = useRef();
const isVisible = usePageVisibility();
useEffect(() => {
const video = videoRef.current;
if (isVisible) {
video.play();
} else {
video.pause();
}
}, [isVisible]);
return (
<video ref={videoRef} width="320" height="240" controls>
<source src={src} type="video/mp4" />
Your browser does not support the video tag.
</video>
);
}
Example: Managing Notifications
Similarly, we can use the usePageVisibility
Hook to manage notifications in our application. For instance, if we have a chat application that displays new message notifications:
import React, { useState, useEffect } from 'react';
import usePageVisibility from './usePageVisibility';
function ChatApp() {
const [messages, setMessages] = useState([]);
const [newMessageCount, setNewMessageCount] = useState(0);
const isVisible = usePageVisibility();
useEffect(() => {
// Subscribe to new messages from the chat API
function handleNewMessage(message) {
setMessages((prevMessages) => [...prevMessages, message]);
if (!isVisible) {
setNewMessageCount((prevCount) => prevCount + 1);
}
}
// Subscribe to the chat API
const unsubscribe = chatApi.subscribe(handleNewMessage);
return () => {
// Unsubscribe from the chat API when the component is unmounted
unsubscribe();
};
}, [isVisible]);
return <div>{/* Render the chat messages and new message count here */}</div>;
}
Conclusion
The Page Visibility API is a valuable tool for detecting the visibility state of a webpage. By listening to the visibilitychange
event and using the document.visibilityState
property, developers can perform various actions depending on the page's visibility. Additionally, creating a custom React Hook, such as usePageVisibility
, allows for more convenient and efficient use of the API within React applications.
Thanks for reading. If you like such stories and want to support me, please consider becoming a Medium member. It costs $5 per month and gives unlimited access to Medium content. I’ll get a little commission if you sign up via my link.
Build React Apps with reusable components, just like Lego
Bit’s open-source tool help 250,000+ devs to build apps with components.
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want: