React-visibility-sensor is a lightweight and flexible React component designed to detect whether its child element is currently visible within the user's viewport. It's an invaluable tool for implementing various performance optimizations and user experience enhancements, such as lazy loading content, triggering animations when elements scroll into view, or tracking user engagement.
How it Works:
At its core, `react-visibility-sensor` works by attaching event listeners to scroll and resize events of the window (or a specified scrollable container). When these events occur, it calculates the position and dimensions of its wrapped child element relative to the viewport. Based on these calculations, it determines if the element is currently visible and invokes a callback function provided via its `onChange` prop.
Key Features and Props:
* `onChange(isVisible: boolean)`: The most crucial prop, this callback function is triggered whenever the visibility status of the child element changes. It receives a single boolean argument, `isVisible`, indicating whether the element is currently visible.
* `partialVisibility (boolean)`: If set to `true`, the sensor will report `isVisible` as `true` even if only a portion of the wrapped element is visible within the viewport. By default, it's `false`, meaning the entire element must be visible.
* `offset (object)`: Allows defining a custom offset around the viewport. For example, `{ top: -100 }` would mean the element is considered visible 100 pixels *before* it actually enters the top of the viewport. This is useful for pre-loading content slightly ahead of time.
* `minTopValue (number)`: Specifies the minimum number of pixels from the top of the element that must be visible for `isVisible` to be true. Useful when `partialVisibility` is true.
* `intervalCheck (boolean)`: If `true` (default), the sensor will also perform periodic checks in addition to reacting to scroll/resize events. This can catch cases where element positions change without a scroll/resize (though less common).
* `intervalDelay (number)`: The delay in milliseconds between interval checks if `intervalCheck` is true.
* `scrollCheck`, `resizeCheck`, `shouldCheckOnMount`: Boolean props to control when visibility checks are performed (on scroll, on resize, or immediately after mounting).
* `containment (HTMLElement)`: Allows specifying a custom scrollable parent element (e.g., a `div` with `overflow: scroll`) instead of the entire window for visibility calculations.
Common Use Cases:
1. Lazy Loading Images/Components: Load heavy assets only when they enter the viewport, improving initial page load times.
2. Animations: Trigger CSS animations or JavaScript effects when elements become visible, creating dynamic user interfaces.
3. Infinite Scrolling: Detect when the last item in a list enters the viewport to fetch more data.
4. Analytics/Tracking: Log events when specific content comes into view to understand user engagement.
Installation:
`npm install react-visibility-sensor` or `yarn add react-visibility-sensor`.
Example Code
import React, { useState } from 'react';
import VisibilitySensor from 'react-visibility-sensor';
function LazyImageLoader() {
const [isVisible, setIsVisible] = useState(false);
const [imageSrc, setImageSrc] = useState('');
const handleVisibilityChange = (visible) => {
setIsVisible(visible);
if (visible && !imageSrc) {
console.log('Element is visible! Loading image...');
// Simulate network request or direct assignment of image source
setTimeout(() => {
setImageSrc('https://via.placeholder.com/400/87CEEB/FFFFFF?text=Lazy+Loaded+Image');
}, 1000); // Simulate 1-second loading delay
}
};
return (
<div style={{ textAlign: 'center' }}>
<h1 style={{ marginBottom: '100vh' }}>Scroll Down to Load Image</h1>
<VisibilitySensor
onChange={handleVisibilityChange}
partialVisibility={true} // Consider element visible if even partially in view
offset={{ bottom: -200 }} // Trigger 200px before the element's bottom enters viewport
minTopValue={100} // At least 100px from the top of the element must be visible
>
<div
style={{
minHeight: '300px',
width: '80%',
margin: '50px auto',
backgroundColor: isVisible ? '#e0ffe0' : '#f0f0f0',
border: `2px dashed ${isVisible ? 'green' : 'gray'}`,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'background-color 0.5s ease, border-color 0.5s ease',
fontSize: '1.2em',
color: isVisible ? '#333' : '#666',
}}
>
{imageSrc ? (
<img
src={imageSrc}
alt="Dynamically loaded content"
style={{ maxWidth: '100%', maxHeight: '100%', display: 'block' }}
/>
) : (
<p>{isVisible ? 'Loading image...' : 'Scroll into view to load image'}</p>
)}
</div>
</VisibilitySensor>
<p style={{ marginTop: '100vh' }}>End of Content</p>
</div>
);
}
export default LazyImageLoader;








react-visibility-sensor