React Measure
react-measure is a React component that efficiently computes the dimensions and position of its child components. It leverages the browser's native `ResizeObserver` API to detect element dimension changes, offering a performant alternative to traditional polling or window resize event listeners. The library includes a polyfill for `ResizeObserver` to ensure broad browser compatibility across different environments. Currently stable at version 2.5.2, `react-measure` functions as a render prop component, allowing developers to precisely specify which rectangle properties (such as `client`, `offset`, `scroll`, `bounds`, or `margin`) are needed. Its key differentiator is the `ResizeObserver` integration, providing accurate and efficient measurement updates with minimal overhead, suitable for responsive designs and component queries. The package has been in a maintenance phase since its last major updates, providing a stable and reliable utility.
Common errors
-
TypeError: Children must be a function.
cause The `Measure` component expects a function as its direct child, implementing the render prop pattern.fixWrap your component logic within a function passed as a child to `Measure`: `<Measure>{({ measureRef }) => (<div ref={measureRef}>...</div>)}</Measure>`. -
Uncaught TypeError: Cannot read properties of undefined (reading 'measureRef')
cause This error often occurs when the render prop function's arguments are destructured incorrectly or `measureRef` is used outside the scope of the render prop.fixEnsure `measureRef` is correctly destructured from the render prop's arguments: `{({ measureRef, contentRect }) => ...}` and used within that function's scope. -
ResizeObserver loop limit exceeded
cause While `react-measure` aims to prevent this, continuous updates within the `onResize` callback that themselves cause layout changes can lead to an infinite loop, especially if styles are directly manipulated based on measurements without proper debounce or condition checks.fixCarefully manage state updates within the `onResize` handler. Ensure that style changes based on measurements do not create a feedback loop that continuously triggers new resize events. Consider debouncing the `onResize` callback if you're performing heavy DOM manipulations or complex state updates.
Warnings
- gotcha The `onResize` callback is typically invoked twice on initial mount. The first call comes from `componentDidMount` with initial values, and the second from the `ResizeObserver` once it has established its observation. Consumers should account for this behavior if precise initialization logic is required.
- gotcha `react-measure` requires its `children` prop to be a function, following the render prop pattern. Providing anything other than a function will result in a runtime error.
- gotcha To correctly measure a component, the `measureRef` prop received from the `Measure` render prop must be passed down to the `ref` of the actual DOM element you intend to measure. Failing to do so will prevent `react-measure` from obtaining a valid node.
Install
-
npm install react-measure -
yarn add react-measure -
pnpm add react-measure
Imports
- Measure
import { Measure } from 'react-measure';import Measure from 'react-measure';
- Measure (CJS)
const Measure = require('react-measure'); - UMD Global
const Measure = ReactMeasure;
Quickstart
import React, { Component } from 'react';
import Measure from 'react-measure';
import classNames from 'classnames';
class ItemToMeasure extends Component {
state = {
dimensions: {
width: -1,
height: -1,
},
};
render() {
const { width, height } = this.state.dimensions;
// Example of a responsive class name based on width
const className = classNames('measured-item', {
'small-width-modifier': width < 400 && width !== -1,
'medium-width-modifier': width >= 400 && width < 800,
'large-width-modifier': width >= 800,
});
return (
<Measure
bounds // Request bounding client rect measurements
margin // Request computed margin properties
onResize={(contentRect) => {
this.setState({
dimensions: contentRect.bounds,
});
console.log('Component resized:', contentRect.bounds);
}}
>
{({ measureRef, contentRect }) => (
<div ref={measureRef} className={className} style={{ padding: '20px', border: '1px solid #ccc', minHeight: '100px' }}>
<p>I am a component being measured!</p>
{contentRect.bounds.width !== -1 && (
<div>
<p>Width: {Math.round(contentRect.bounds.width)}px</p>
<p>Height: {Math.round(contentRect.bounds.height)}px</p>
</div>
)}
<div style={{ background: '#eee', padding: '10px', marginTop: '10px' }}>
Current Class: {className}
</div>
</div>
)}
</Measure>
);
}
}
// To run this, you'd typically render ItemToMeasure in a React root:
// ReactDOM.render(<ItemToMeasure />, document.getElementById('root'));
export default ItemToMeasure;