react-cool-dimensions
3.0.1 • Public • PublishedREACT COOL DIMENSIONS
A Reacthook that measure an element's size and handleresponsive components with highly-performant way, usingResizeObserver. Try it you will 👍🏻 it!
Features
🚀 Measures element's size with highly-performant way, usingResizeObserver.🎣 Easy to use, based on Reacthook.🍰 Easy to handleresponsive components, provides an alternative solution to thecontainer queries problem.📦 Supportsborder-box size measurement.🕹 Supportsconditionally updating state.🎛 Super flexibleAPI design to cover most cases for you.📜 SupportsTypeScript type definition.🗄️ Server-side rendering compatibility.🦔 Tiny size (~ 1kB gzipped). No external dependencies, aside for thereact.
Requirement
To usereact-cool-dimensions, you must usereact@16.8.0 or greater which includes hooks.
Installation
This package is distributed vianpm.
$ yarn add react-cool-dimensions# or$ npm install --save react-cool-dimensionsUsage
react-cool-dimensions has a flexibleAPI design, it can cover simple to complex use cases for you. Here are some examples to show you how does it work.
⚠️ Most modern browsers support ResizeObserver natively. You can also usepolyfill for full browser support.
Basic Use Case
To report the size of an element by thewidth andheight states.
importuseDimensionsfrom"react-cool-dimensions";constApp=()=>{const{ observe, unobserve, width, height, entry}=useDimensions({onResize:({ observe, unobserve, width, height, entry})=>{// Triggered whenever the size of the target is changed...unobserve();// To stop observing the current target elementobserve();// To re-start observing the current target element},});return(<divref={observe}> Hi! My width is{width}px and height is{height}px</div>);};
💡 You don't have to callunobservewhen the component is unmounted, this hook will handle it for you.
Responsive Components
We havemedia queries but those are based on the browser viewport not individual elements. In some cases, we'd like to style components based on the width of a containing element rather than the browser viewport. To meet this demand there's aproposal forcontainer queries, but it still doesn't exist today...
No worries,react-cool-dimensions provides an alternative solution for us! We can activate theresponsive mode by thebreakpoints option. It's a width-based solution, once it's activated we can easily apply different styles to a component according to thecurrentBreakpoint state. The overall concept as below.
If you wish to update the state on the breakpoints changed, you can set theupdateOnBreakpointChange option totrue.
importuseDimensionsfrom"react-cool-dimensions";constCard=()=>{const{ observe, currentBreakpoint}=useDimensions({// The "currentBreakpoint" will be the object key based on the target's width// for instance, 0px - 319px (currentBreakpoint = XS), 320px - 479px (currentBreakpoint = SM) and so onbreakpoints:{XS:0,SM:320,MD:480,LG:640},// Will only update the state on breakpoint changed, default is falseupdateOnBreakpointChange:true,onResize:({ currentBreakpoint})=>{// Now the event callback will be triggered when breakpoint is changed// we can also access the "currentBreakpoint" here},});return(<divclass={`card${currentBreakpoint}`}ref={observe}><divclass="card-header">I'm 😎</div><divclass="card-body">I'm 👕</div><divclass="card-footer">I'm 👟</div></div>);};
Note: If the
breakpointsoption isn't set or there's no the defined breakpoint (object key) for a range of width. ThecurrentBreakpointwill be empty string.
Conditionally Updating State
You can use theshouldUpdate option to conditionally update the state to reduce unnecessary re-renders as below.
constreturnObj=useDimensions({shouldUpdate:({ currentBreakpoint, width, height, entry})=>{// Will only update the state when the target element's width greater than 300pxreturnstate.width>300;},});
Note: When
updateOnBreakpointChangeandshouldUpdateare used at the same time,shouldUpdatehas a higher priority.
Border-box Size Measurement
By default, the hook reports thewidth andheight based on thecontent rectangle of the target element. We can include the padding and border for measuring by theuseBorderBoxSize option. Please note, thewidth andheight states are rely on theResizeObserverEntry.borderBoxSize butit hasn't widely implemented by browsers therefore we need to usepolyfill for this feature.
importuseDimensionsfrom"react-cool-dimensions";import{ResizeObserver}from"@juggle/resize-observer";constApp=()=>{const{ observe, width, height}=useDimensions({useBorderBoxSize:true,// Tell the hook to measure based on the border-box size, default is falsepolyfill:ResizeObserver,// Use polyfill to make this feature works on more browsers});return(<divstyle={{width:"100px",height:"100px",padding:"10px",border:"5px solid grey",}}ref={observe}>{/* Now the width and height will be: 100px + 10px + 5px = 115px */} Hi! My width is{width}px and height is{height}px</div>);};
How to Share Aref?
You can share aref as follows:
import{useRef}from"react";importuseDimensionsfrom"react-cool-dimensions";constApp=()=>{constref=useRef();const{ observe}=useDimensions();return(<divref={(el)=>{observe(el);// Set the target element for measuringref.current=el;// Share the element for other purposes}}/>);};
Performance Optimization
TheonResize event will be triggered whenever the size of the target element is changed. We can reduce the frequency of the event callback by activating theresponsive mode or implementing our own throttled/debounced function as below. Note that in order to throttle/debounce the function correctly, it will need to be memorized else it will be recreated on every render call.
import{useMemo}from"react";import_from"lodash";constreturnObj=useDimensions({onResize:useMemo(()=>_.throttle(()=>{// Triggered once per every 500 milliseconds},500),[]),});
Working in TypeScript
This hook supportsTypeScript, you can tell the hook what type of element you are going to observe through thegeneric type:
constApp=()=>{const{ observe}=useDimensions<HTMLDivElement>();return<divref={observe}/>;};
💡 For more available types, pleasecheck it out.
API
constreturnObj=useDimensions(options?:object);
Return object
It's returned with the following properties.
| Key | Type | Default | Description |
|---|---|---|---|
observe | function | To set a target element for measuring or re-start observing the current target element. | |
unobserve | function | To stop observing the current target element. | |
width | number or null | null | The width of the target element in pixel. Null while target has not mounted. |
height | number or null | null | The height of the target element in pixel. Null while target has not mounted.Z |
currentBreakpoint | string | Indicates the current breakpoint of theresponsive components. | |
entry | object | TheResizeObserverEntry of the target element. |
Parameter
Theoptions provides the following configurations and event callback for you.
| Key | Type | Default | Description |
|---|---|---|---|
breakpoints | object | Activates the responsive mode forresponsive components orperformance optimization. | |
updateOnBreakpointChange | boolean | false | Tells the hook to update the state on breakpoint changed. |
useBorderBoxSize | boolean | false | Tells the hook tomeasure the target element based on the border-box size. |
shouldUpdate | function | Tells the hook toconditionally update the state. | |
onResize | function | It's invoked whenever the size of the target element is changed. But inresponsive mode, it's invoked based on the changing of the breakpoint rather than the size. | |
polyfill | ResizeObserver | It's used forinjecting a polyfill. |
ResizeObserver Polyfill
ResizeObserver has good support amongst browsers, but it's not universal. You'll need to use polyfill for browsers that don't support it. Polyfills is something you should do consciously at the application level. Thereforereact-cool-dimensions doesn't include it.
We recommend using@juggle/resize-observer:
$ yarn add @juggle/resize-observer# or$ npm install --save @juggle/resize-observerThen inject it by thepolyfill option:
import{ResizeObserver}from"@juggle/resize-observer";const{ width, height}=useDimensions(ref,{polyfill:ResizeObserver});
Or pollute thewindow object:
import{ResizeObserver,ResizeObserverEntry}from"@juggle/resize-observer";if(!("ResizeObserver"inwindow)){window.ResizeObserver=ResizeObserver;// Only use it when you have this trouble: https://github.com/wellyshen/react-cool-dimensions/issues/45// window.ResizeObserverEntry = ResizeObserverEntry;}
You could use dynamic imports to only load the file when the polyfill is required:
(async()=>{if(!("ResizeObserver"inwindow)){constmodule=awaitimport("@juggle/resize-observer");window.ResizeObserver=module.ResizeObserver;// Only use it when you have this trouble: https://github.com/wellyshen/react-cool-dimensions/issues/45// window.ResizeObserverEntry = module.ResizeObserverEntry;}})();
Articles / Blog Posts
💡 If you have written any blog post or article aboutreact-cool-dimensions, please open a PR to add it here.
- Featured onReact Status #191.
Contributors✨
Thanks goes to these wonderful people (emoji key):
Welly | Runar Kristoffersen | Ricardo Amaral | Cornelius | Joseph Horton | sirkrisp |
This project follows theall-contributors specification. Contributions of any kind welcome!
Package Sidebar
Install
npm i react-cool-dimensions
Weekly Downloads
47,900
Version
3.0.1
License
MIT
Unpacked Size
53.3 kB
Total Files
8
