New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

use-resize-observer

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

use-resize-observer - npm Package Compare versions

Comparing version 6.1.0 to 6.2.0-alpha.1

CONTRIBUTING.md

12

.size-limit.json
[
{
"path": "dist/bundle.esm.js",
"limit": "357 B",
"limit": "499 B",
"gzip": true

@@ -9,3 +9,3 @@ },

"path": "dist/bundle.esm.js",
"limit": "281 B",
"limit": "404 B",
"brotli": true

@@ -15,3 +15,3 @@ },

"path": "dist/bundle.cjs.js",
"limit": "346 B",
"limit": "485 B",
"gzip": true

@@ -21,3 +21,3 @@ },

"path": "dist/bundle.cjs.js",
"limit": "261 B",
"limit": "387 B",
"brotli": true

@@ -27,3 +27,3 @@ },

"path": "polyfilled.js",
"limit": "2678 B",
"limit": "2809 B",
"gzip": true

@@ -33,5 +33,5 @@ },

"path": "polyfilled.js",
"limit": "2381 B",
"limit": "2512 B",
"brotli": true
}
]
# CHANGELOG
## 6.2.0-alpha.1
- Only instantiating a ResizeObserver instance if there's actually something to
observe. This for example means that if you pass in `null` or undefined as the
ref, or if neither the default ref or callback ref returned from the hook are
in use, then no ResizeObserver instance will get created until there's an
actual element to observe. Resolves: #42
- The hook now returns `callbackRef`, which can be used in place of the usual
`ref`. Use this instead of a normal ref, when the observed component is
mounted with a delay. Resolves: #43, #45
- The `ref` option now accepts raw elements as well.
- Handling custom refs (through options), the default ref and the callback ref
has been greatly refactored internally (into the `useResolvedElement`
hook), to handle more edge cases with the way refs are handled.
- Tests based on react testing library were refactored to make them much simpler
and more approachable.
- Fixed an error where in certain edge cases the hook tried to set state when
its host component already unmounted.
- Added [contributing guidelines](./CONTRIBUTING.md)
- Overall bundle size increased a bit, due to the new features added.
(With about ~150B or so.)
## 6.1.0

@@ -7,7 +29,7 @@

## 6.1.0-alpha3
## 6.1.0-alpha.3
- Fixed SSR rendering, and added a test to cover it.
## 6.1.0-alpha2
## 6.1.0-alpha.2

@@ -18,3 +40,3 @@ - ResizeObserver instances are no longer created unnecessarily when the onResize

## 6.1.0-alpha1
## 6.1.0-alpha.1

@@ -21,0 +43,0 @@ - Rewrote the source in TypeScript. (Feedback is welcome.)

@@ -5,2 +5,69 @@ 'use strict';

// This of course could've been more streamlined with internal state instead of
// refs, but then host hooks / components could not opt out of renders.
// This could've been exported to its own module, but the current build doesn't
// seem to work with module imports and I had no more time to spend on this...
function useResolvedElement(subscriber, refOrElement) {
// The default ref has to be non-conditionally declared here whether or not
// it'll be used as that's how hooks work.
// @see https://reactjs.org/docs/hooks-rules.html#explanation
var ref = react.useRef(null); // Default ref
var refElement = react.useRef(null);
var callbackRefElement = react.useRef(null);
var callbackRef = react.useCallback(function (element) {
callbackRefElement.current = element;
callSubscriber();
}, []);
var lastReportedElementRef = react.useRef(null);
var cleanupRef = react.useRef();
var callSubscriber = function callSubscriber() {
var element = null;
if (callbackRefElement.current) {
element = callbackRefElement.current;
} else if (refElement.current) {
element = refElement.current;
} else if (refOrElement instanceof HTMLElement) {
element = refOrElement;
}
if (lastReportedElementRef.current === element) {
return;
}
if (cleanupRef.current) {
cleanupRef.current();
}
lastReportedElementRef.current = element; // Only calling the subscriber, if there's an actual element to report.
if (element) {
cleanupRef.current = subscriber(element);
}
};
if (refOrElement && !(refOrElement instanceof HTMLElement)) {
// Overriding the default ref with the given one
ref = refOrElement;
} // On each render, we check whether a ref changed, or if we got a new raw
// element.
react.useEffect(function () {
// Note that this does not mean that "element" will necessarily be whatever
// the ref currently holds. It'll simply "update" `element` each render to
// the current ref value, but there's no guarantee that the ref value will
// not change later without a render.
// This may or may not be a problem depending on the specific use case.
refElement.current = ref.current;
callSubscriber();
}, [ref, ref.current, refOrElement]);
return {
ref: ref,
callbackRef: callbackRef
};
}
function useResizeObserver(opts) {

@@ -11,15 +78,10 @@ if (opts === void 0) {

// `defaultRef` Has to be non-conditionally declared here whether or not it'll
// be used as that's how hooks work.
// @see https://reactjs.org/docs/hooks-rules.html#explanation
var defaultRef = react.useRef(null); // Saving the callback as a ref. With this, I don't need to put onResize in the
// Saving the callback as a ref. With this, I don't need to put onResize in the
// effect dep array, and just passing in an anonymous function without memoising
// will not reinstantiate the hook's ResizeObserver
var onResize = opts.onResize;
var onResizeRef = react.useRef(undefined);
onResizeRef.current = onResize; // Using a single instance throughought the hook's lifetime
onResizeRef.current = onResize; // Using a single instance throughout the hook's lifetime
var resizeObserverRef = react.useRef();
var ref = opts.ref || defaultRef;

@@ -31,66 +93,80 @@ var _useState = react.useState({

size = _useState[0],
setSize = _useState[1]; // Using a ref to track the previous width / height to avoid unnecessary renders
setSize = _useState[1]; // In certain edge cases the RO might want to report a size change just after
// the component unmounted.
var didUnmount = react.useRef(false);
react.useEffect(function () {
return function () {
didUnmount.current = true;
};
}, []); // Using a ref to track the previous width / height to avoid unnecessary renders
var previous = react.useRef({
width: undefined,
height: undefined
});
react.useEffect(function () {
if (resizeObserverRef.current) {
return;
}
}); // This block is kinda like a useEffect, only it's called whenever a new
// element could be resolved based on the ref option. It also has a cleanup
// function.
resizeObserverRef.current = new ResizeObserver(function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
var _useResolvedElement = useResolvedElement(function (element) {
// Initialising the RO instance
if (!resizeObserverRef.current) {
// Saving a single instance, used by the hook from this point on.
resizeObserverRef.current = new ResizeObserver(function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
if (!entries.length) {
return;
}
if (!entries.length) {
return;
}
var entry = entries[0]; // `Math.round` is in line with how CSS resolves sub-pixel values
var entry = entries[0]; // `Math.round` is in line with how CSS resolves sub-pixel values
var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
setSize(newSize);
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
if (!didUnmount.current) {
setSize(newSize);
}
}
}
}
});
}, []);
react.useEffect(function () {
if (typeof ref !== "object" || ref === null || !(ref.current instanceof Element)) {
return;
});
}
var element = ref.current;
resizeObserverRef.current.observe(element);
return function () {
return resizeObserverRef.current.unobserve(element);
if (resizeObserverRef.current) {
resizeObserverRef.current.unobserve(element);
}
};
}, [ref]);
}, opts.ref),
ref = _useResolvedElement.ref,
callbackRef = _useResolvedElement.callbackRef;
return react.useMemo(function () {
return {
ref: ref,
callbackRef: callbackRef,
width: size.width,
height: size.height
};
}, [ref, size ? size.width : null, size ? size.height : null]);
}, [ref, callbackRef, size ? size.width : null, size ? size.height : null]);
}
module.exports = useResizeObserver;

@@ -1,3 +0,70 @@

import { useRef, useState, useEffect, useMemo } from 'react';
import { useRef, useState, useEffect, useMemo, useCallback } from 'react';
// This of course could've been more streamlined with internal state instead of
// refs, but then host hooks / components could not opt out of renders.
// This could've been exported to its own module, but the current build doesn't
// seem to work with module imports and I had no more time to spend on this...
function useResolvedElement(subscriber, refOrElement) {
// The default ref has to be non-conditionally declared here whether or not
// it'll be used as that's how hooks work.
// @see https://reactjs.org/docs/hooks-rules.html#explanation
var ref = useRef(null); // Default ref
var refElement = useRef(null);
var callbackRefElement = useRef(null);
var callbackRef = useCallback(function (element) {
callbackRefElement.current = element;
callSubscriber();
}, []);
var lastReportedElementRef = useRef(null);
var cleanupRef = useRef();
var callSubscriber = function callSubscriber() {
var element = null;
if (callbackRefElement.current) {
element = callbackRefElement.current;
} else if (refElement.current) {
element = refElement.current;
} else if (refOrElement instanceof HTMLElement) {
element = refOrElement;
}
if (lastReportedElementRef.current === element) {
return;
}
if (cleanupRef.current) {
cleanupRef.current();
}
lastReportedElementRef.current = element; // Only calling the subscriber, if there's an actual element to report.
if (element) {
cleanupRef.current = subscriber(element);
}
};
if (refOrElement && !(refOrElement instanceof HTMLElement)) {
// Overriding the default ref with the given one
ref = refOrElement;
} // On each render, we check whether a ref changed, or if we got a new raw
// element.
useEffect(function () {
// Note that this does not mean that "element" will necessarily be whatever
// the ref currently holds. It'll simply "update" `element` each render to
// the current ref value, but there's no guarantee that the ref value will
// not change later without a render.
// This may or may not be a problem depending on the specific use case.
refElement.current = ref.current;
callSubscriber();
}, [ref, ref.current, refOrElement]);
return {
ref: ref,
callbackRef: callbackRef
};
}
function useResizeObserver(opts) {

@@ -8,15 +75,10 @@ if (opts === void 0) {

// `defaultRef` Has to be non-conditionally declared here whether or not it'll
// be used as that's how hooks work.
// @see https://reactjs.org/docs/hooks-rules.html#explanation
var defaultRef = useRef(null); // Saving the callback as a ref. With this, I don't need to put onResize in the
// Saving the callback as a ref. With this, I don't need to put onResize in the
// effect dep array, and just passing in an anonymous function without memoising
// will not reinstantiate the hook's ResizeObserver
var onResize = opts.onResize;
var onResizeRef = useRef(undefined);
onResizeRef.current = onResize; // Using a single instance throughought the hook's lifetime
onResizeRef.current = onResize; // Using a single instance throughout the hook's lifetime
var resizeObserverRef = useRef();
var ref = opts.ref || defaultRef;

@@ -28,66 +90,80 @@ var _useState = useState({

size = _useState[0],
setSize = _useState[1]; // Using a ref to track the previous width / height to avoid unnecessary renders
setSize = _useState[1]; // In certain edge cases the RO might want to report a size change just after
// the component unmounted.
var didUnmount = useRef(false);
useEffect(function () {
return function () {
didUnmount.current = true;
};
}, []); // Using a ref to track the previous width / height to avoid unnecessary renders
var previous = useRef({
width: undefined,
height: undefined
});
useEffect(function () {
if (resizeObserverRef.current) {
return;
}
}); // This block is kinda like a useEffect, only it's called whenever a new
// element could be resolved based on the ref option. It also has a cleanup
// function.
resizeObserverRef.current = new ResizeObserver(function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
var _useResolvedElement = useResolvedElement(function (element) {
// Initialising the RO instance
if (!resizeObserverRef.current) {
// Saving a single instance, used by the hook from this point on.
resizeObserverRef.current = new ResizeObserver(function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
if (!entries.length) {
return;
}
if (!entries.length) {
return;
}
var entry = entries[0]; // `Math.round` is in line with how CSS resolves sub-pixel values
var entry = entries[0]; // `Math.round` is in line with how CSS resolves sub-pixel values
var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
setSize(newSize);
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
if (!didUnmount.current) {
setSize(newSize);
}
}
}
}
});
}, []);
useEffect(function () {
if (typeof ref !== "object" || ref === null || !(ref.current instanceof Element)) {
return;
});
}
var element = ref.current;
resizeObserverRef.current.observe(element);
return function () {
return resizeObserverRef.current.unobserve(element);
if (resizeObserverRef.current) {
resizeObserverRef.current.unobserve(element);
}
};
}, [ref]);
}, opts.ref),
ref = _useResolvedElement.ref,
callbackRef = _useResolvedElement.callbackRef;
return useMemo(function () {
return {
ref: ref,
callbackRef: callbackRef,
width: size.width,
height: size.height
};
}, [ref, size ? size.width : null, size ? size.height : null]);
}, [ref, callbackRef, size ? size.width : null, size ? size.height : null]);
}
export default useResizeObserver;

@@ -1,2 +0,2 @@

import { RefObject } from "react";
import { RefObject, RefCallback } from "react";
declare type ObservedSize = {

@@ -7,13 +7,17 @@ width: number | undefined;

declare type ResizeHandler = (size: ObservedSize) => void;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
onResize?: ResizeHandler;
}): {
declare type HookResponse<T extends HTMLElement> = {
ref: RefObject<T>;
callbackRef: RefCallback<T>;
} & ObservedSize;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
onResize?: ResizeHandler;
}): HookResponse<T>;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
ref: RefObject<T>;
onResize?: ResizeHandler;
}): {
ref: RefObject<T>;
} & ObservedSize;
}): HookResponse<T>;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
ref: RefObject<T> | T | null | undefined;
onResize?: ResizeHandler;
}): HookResponse<T>;
export default useResizeObserver;
{
"name": "use-resize-observer",
"version": "6.1.0",
"version": "6.2.0-alpha.1",
"main": "dist/bundle.cjs.js",

@@ -48,5 +48,6 @@ "module": "dist/bundle.esm.js",

"@babel/preset-typescript": "^7.9.0",
"@rollup/plugin-babel": "^5.2.1",
"@rollup/plugin-inject": "^4.0.1",
"@size-limit/preset-small-lib": "^4.4.5",
"@testing-library/react": "^10.0.2",
"@testing-library/react": "^11.0.4",
"@types/karma": "^5.0.0",

@@ -62,3 +63,3 @@ "@types/karma-jasmine": "^3.1.0",

"karma-firefox-launcher": "^1.3.0",
"karma-jasmine": "^3.1.1",
"karma-jasmine": "^4.0.1",
"karma-sourcemap-loader": "^0.3.7",

@@ -73,5 +74,4 @@ "karma-spec-reporter": "^0.0.32",

"rollup": "^2.6.1",
"rollup-plugin-babel": "^4.4.0",
"size-limit": "^4.4.5",
"typescript": "^3.8.3"
"typescript": "^4.0.3"
},

@@ -78,0 +78,0 @@ "dependencies": {

@@ -1,2 +0,2 @@

import { RefObject } from "react";
import { RefObject, RefCallback } from "react";
declare type ObservedSize = {

@@ -7,13 +7,17 @@ width: number | undefined;

declare type ResizeHandler = (size: ObservedSize) => void;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
onResize?: ResizeHandler;
}): {
declare type HookResponse<T extends HTMLElement> = {
ref: RefObject<T>;
callbackRef: RefCallback<T>;
} & ObservedSize;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
onResize?: ResizeHandler;
}): HookResponse<T>;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
ref: RefObject<T>;
onResize?: ResizeHandler;
}): {
ref: RefObject<T>;
} & ObservedSize;
}): HookResponse<T>;
declare function useResizeObserver<T extends HTMLElement>(opts?: {
ref: RefObject<T> | T | null | undefined;
onResize?: ResizeHandler;
}): HookResponse<T>;
export default useResizeObserver;
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var ResizeObserver = _interopDefault(require('resize-observer-polyfill'));
var ResizeObserver = require('resize-observer-polyfill');
var react = require('react');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var ResizeObserver__default = /*#__PURE__*/_interopDefaultLegacy(ResizeObserver);
// This of course could've been more streamlined with internal state instead of
// refs, but then host hooks / components could not opt out of renders.
// This could've been exported to its own module, but the current build doesn't
// seem to work with module imports and I had no more time to spend on this...
function useResolvedElement(subscriber, refOrElement) {
// The default ref has to be non-conditionally declared here whether or not
// it'll be used as that's how hooks work.
// @see https://reactjs.org/docs/hooks-rules.html#explanation
var ref = react.useRef(null); // Default ref
var refElement = react.useRef(null);
var callbackRefElement = react.useRef(null);
var callbackRef = react.useCallback(function (element) {
callbackRefElement.current = element;
callSubscriber();
}, []);
var lastReportedElementRef = react.useRef(null);
var cleanupRef = react.useRef();
var callSubscriber = function callSubscriber() {
var element = null;
if (callbackRefElement.current) {
element = callbackRefElement.current;
} else if (refElement.current) {
element = refElement.current;
} else if (refOrElement instanceof HTMLElement) {
element = refOrElement;
}
if (lastReportedElementRef.current === element) {
return;
}
if (cleanupRef.current) {
cleanupRef.current();
}
lastReportedElementRef.current = element; // Only calling the subscriber, if there's an actual element to report.
if (element) {
cleanupRef.current = subscriber(element);
}
};
if (refOrElement && !(refOrElement instanceof HTMLElement)) {
// Overriding the default ref with the given one
ref = refOrElement;
} // On each render, we check whether a ref changed, or if we got a new raw
// element.
react.useEffect(function () {
// Note that this does not mean that "element" will necessarily be whatever
// the ref currently holds. It'll simply "update" `element` each render to
// the current ref value, but there's no guarantee that the ref value will
// not change later without a render.
// This may or may not be a problem depending on the specific use case.
refElement.current = ref.current;
callSubscriber();
}, [ref, ref.current, refOrElement]);
return {
ref: ref,
callbackRef: callbackRef
};
}
function useResizeObserver(opts) {

@@ -13,15 +82,10 @@ if (opts === void 0) {

// `defaultRef` Has to be non-conditionally declared here whether or not it'll
// be used as that's how hooks work.
// @see https://reactjs.org/docs/hooks-rules.html#explanation
var defaultRef = react.useRef(null); // Saving the callback as a ref. With this, I don't need to put onResize in the
// Saving the callback as a ref. With this, I don't need to put onResize in the
// effect dep array, and just passing in an anonymous function without memoising
// will not reinstantiate the hook's ResizeObserver
var onResize = opts.onResize;
var onResizeRef = react.useRef(undefined);
onResizeRef.current = onResize; // Using a single instance throughought the hook's lifetime
onResizeRef.current = onResize; // Using a single instance throughout the hook's lifetime
var resizeObserverRef = react.useRef();
var ref = opts.ref || defaultRef;

@@ -33,66 +97,80 @@ var _useState = react.useState({

size = _useState[0],
setSize = _useState[1]; // Using a ref to track the previous width / height to avoid unnecessary renders
setSize = _useState[1]; // In certain edge cases the RO might want to report a size change just after
// the component unmounted.
var didUnmount = react.useRef(false);
react.useEffect(function () {
return function () {
didUnmount.current = true;
};
}, []); // Using a ref to track the previous width / height to avoid unnecessary renders
var previous = react.useRef({
width: undefined,
height: undefined
});
react.useEffect(function () {
if (resizeObserverRef.current) {
return;
}
}); // This block is kinda like a useEffect, only it's called whenever a new
// element could be resolved based on the ref option. It also has a cleanup
// function.
resizeObserverRef.current = new ResizeObserver(function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
var _useResolvedElement = useResolvedElement(function (element) {
// Initialising the RO instance
if (!resizeObserverRef.current) {
// Saving a single instance, used by the hook from this point on.
resizeObserverRef.current = new ResizeObserver__default['default'](function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
if (!entries.length) {
return;
}
if (!entries.length) {
return;
}
var entry = entries[0]; // `Math.round` is in line with how CSS resolves sub-pixel values
var entry = entries[0]; // `Math.round` is in line with how CSS resolves sub-pixel values
var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
setSize(newSize);
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
if (!didUnmount.current) {
setSize(newSize);
}
}
}
}
});
}, []);
react.useEffect(function () {
if (typeof ref !== "object" || ref === null || !(ref.current instanceof Element)) {
return;
});
}
var element = ref.current;
resizeObserverRef.current.observe(element);
return function () {
return resizeObserverRef.current.unobserve(element);
if (resizeObserverRef.current) {
resizeObserverRef.current.unobserve(element);
}
};
}, [ref]);
}, opts.ref),
ref = _useResolvedElement.ref,
callbackRef = _useResolvedElement.callbackRef;
return react.useMemo(function () {
return {
ref: ref,
callbackRef: callbackRef,
width: size.width,
height: size.height
};
}, [ref, size ? size.width : null, size ? size.height : null]);
}, [ref, callbackRef, size ? size.width : null, size ? size.height : null]);
}
module.exports = useResizeObserver;

@@ -18,8 +18,10 @@ # use-resize-observer

- Written in **TypeScript**.
- **Tiny**: 353 B (minified, gzipped) Monitored by [size-limit](https://github.com/ai/size-limit).
- **Tiny**: 500B (minified, gzipped) Monitored by [size-limit](https://github.com/ai/size-limit).
- Exposes an **onResize callback** if you need more control.
- [Throttle / Debounce](#throttle--debounce)
- Works with **SSR**.
- Works with **CSS-in-JS**.
- **Supports custom refs** in case you [had one already](#passing-in-your-own-ref).
- Handles many edge cases you might not even think of.
(See this documentation and the test cases.)
- [Throttle / Debounce](#throttle--debounce)
- **Tested** in real browsers. (Headless Chrome and Firefox).

@@ -44,3 +46,3 @@

```js
```tsx
import React from "react";

@@ -50,3 +52,3 @@ import useResizeObserver from "use-resize-observer";

const App = () => {
const { ref, width = 1, height = 1 } = useResizeObserver();
const { ref, width = 1, height = 1 } = useResizeObserver<HTMLDivElement>();

@@ -66,5 +68,5 @@ return (

```js
const ref = useRef(null);
const { width, height } = useResizeObserver({ ref });
```ts
const ref = useRef<HTMLDivElement>(null);
const { width, height } = useResizeObserver<HTMLDivElement>({ ref });
```

@@ -76,2 +78,79 @@

## Measuring a raw element
There might be situations where you have an element already that you need to measure.
`ref` now accepts elements as well, not just refs, which means that you can do this:
```ts
const { width, height } = useResizeObserver<HTMLDivElement>({
ref: divElement,
});
```
## Observing components mounted with a delay
Often times you might have to wait before you can mount a component.
Unfortunately if you use a ref, the hook will not be able to pick up its "current"
value being changed afterwards. (Which is by design by React.)
To handle this case, you can do one of these three:
- Use the provided callback ref
- Refactor to a component which you can mount after a "loading" concluded with
the hook within it. This means that the hook will be mounted with the measured
element, which means that a regular ref will work fine.
- Use local state to store the custom ref the hook needs to observe, with "null"
as its starting value. Then once loading concluded, set this state to the ref.
This'll make the hook notice a change from null to the ref, where this time the
ref actually has its current value set properly as well.
([See example here](https://codesandbox.io/s/damp-cookies-6bdrg?file=/src/App.js))
Using a callback ref is recommended, and might look like this:
```tsx
const { callbackRef, width, height } = useResizeObserver<HTMLDivElement>();
const [loaded, setLoaded] = useState(false);
// Simulating a loading state.
useEffect(() => {
setTimeout(() => {
setLoaded(true);
}, 2000);
}, []);
if (!loaded) {
return <div>Loading...</div>;
}
return <div ref={callbackRef}></div>;
```
## Using a single hook to measure multiple refs
The hook reacts to ref changes, as it resolves it to an element to observe.
This means that you can freely change the custom `ref` option from one ref to
another and back, and the hook will start observing whatever is set in its options.
## Opting Out of (or Delaying) ResizeObserver instantiation
In certain cases you might want to delay creating a ResizeObserver instance.
You might provide a library, that only optionally provides observation features
based on props, which means that while you have the hook within your component,
you might not want to actually initialise it.
Another example is that you might want to entirely opt out of initialising, when
you run some tests, where the environment does not provide the `ResizeObserver`.
([See discussions](https://github.com/ZeeCoder/use-resize-observer/issues/40))
You can do one of the following depending on your needs:
- Use a callback ref, or provide a custom ref conditionally, only when needed.
The hook will not create a ResizeObserver instance up until there's something
there to actually observe.
- Patch the test environment, and make a polyfill available as the ResizeObserver.
(This assumes you don't already use the polyfilled version, which would switch
to the polyfill when no native implementation was available.)
## The "onResize" callback

@@ -86,3 +165,3 @@

```js
```tsx
import React from "react";

@@ -93,3 +172,3 @@ import useResizeObserver from "use-resize-observer";

// width / height will not be returned here when the onResize callback is present
const { ref } = useResizeObserver({
const { ref } = useResizeObserver<HTMLDivElement>({
onResize: ({ width, height }) => {

@@ -129,4 +208,4 @@ // do something here.

```js
const { ref, width = 100, height = 50 } = useResizeObserver();
```ts
const { ref, width = 100, height = 50 } = useResizeObserver<HTMLDivElement>();
```

@@ -142,4 +221,4 @@

```js
const { ref, width, height } = useResizeObserver();
```ts
const { ref, width, height } = useResizeObserver<HTMLDivElement>();
```

@@ -146,0 +225,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc