The useSize
hook allows to track size of an element through the ResizeObserver
.
That hook is written with a few technical decisions:
- a single
ResizeObserver
instance used for better performance; - the
requestAnimationFrame
used for throttling resize callbacks; - the hook doesn't support SSR;
-
ResizeObserver
polyfill doesn't used.
Use the package manager pnpm to install @tabula/use-size
.
pnpm add @tabula/use-size
The default usage is looks like:
import { useSize } from '@tabula/use-size';
const Watcher: FC = () => {
const [ref, size] = useSize();
return <div ref={ref} />;
};
The initial value of size will be { height: 0, width: 0 }
.
const [, size] = useSize();
// size => { height: 0, width: 0 }
But you can provide your default value:
const [, size] = useSize({ height: 150, width: 450 });
// size => { height: 150, width: 450 }
That value is actual while have no any element which mounted and transferred to the hook with ref
.
Each time, when a new element is provided through the ref
, we update it's size.
const [ref, size] = useSize();
// size => { height: 0, width: 0 }
ref(<div style={{ height: 150, width: 450 }} />);
// size => { height: 150, width: 450 }
It works each time when element is updated.
const [ref, size] = useSize();
// size => { height: 0, width: 0 }
ref(<div key={0} style={{ height: 150, width: 450 }} />);
// size => { height: 150, width: 450 }
ref(<div key={1} style={{ height: 50, width: 150 }} />);
// size => { height: 50, width: 150 }
Each time when an element is resized, we update it's size in hook.
const [ref, size] = useSize();
// size => { height: 0, width: 0 }
ref(<div style={{ height: 150, width: 450 }} />);
// size => { height: 150, width: 450 }
resize({ height: 50, width: 150 });
// size => { height: 50, width: 150 }
We want to track size of the single element with multiple refs.
const [ref1, size1] = useSize();
const [ref2, size2] = useSize();
const ref = combineRefs(ref1, ref2);
// size1 => { height: 0, width: 0 }
// size2 => { height: 0, width: 0 }
ref(<div style={{ height: 150, width: 450 }} />);
// size1 => { height: 150, width: 450 }
// size2 => { height: 150, width: 450 }
resize({ height: 50, width: 150 });
// size1 => { height: 50, width: 150 }
// size2 => { height: 50, width: 150 }
We always round size object values.
const [ref, size] = useSize();
// size => { height: 0, width: 0 }
ref(<div style={{ height: 150.1, width: 450.9 }} />);
// size => { height: 150, width: 451 }
resize({ height: 50.9, width: 150.1 });
// size => { height: 51, width: 150 }
We try to avoid re-renders. If a new size is equal to previous, we don't trigger re-render.
const [ref, size] = useSize();
// size => { height: 0, width: 0 }
// render
ref(<div style={{ height: 150, width: 450 }} />);
// size => { height: 150, width: 450 }
// render
resize({ height: 150, width: 450 });
// size => { height: 150, width: 450 }
// no render
resize({ height: 150.1, width: 450.1 })
// size => { height: 150, width: 450 }
// no render
You can get access to the target element through hook.
const [ref, size, target] = useSize();
// target => null
ref(<div id="target-1" />);
// target => <div id="target-1" />
ref(<div id="target-2" />);
// target => <div id="target-2" />
ref(null);
// target => null
This package is inspired by:
This project is ISC licensed.