Implement a react component that automatically calculates width and height based on ResizeObserver
Tags: react, javascript, webdev, github
Published: 2022-01-11 14:42:22


## 🏠 [Homepage](https://niexq.github.io/react-auto-sizer)

![Homepage](https://raw.githubusercontent.com/niexq/picbed/main/picgo/homepageen.gif)

## 📦 Install

```bash
  yarn add @oyyds/react-auto-sizer  # or npm i @oyyds/react-auto-sizer -S
```

## 🔨 Use

```js
import AutoSizer from '@oyyds/react-auto-sizer';

const AutoSizeComponent = () => {
  return (
    <div>
      <AutoSizer>
        {({ width, height }) => (
          <div
            style={{
              width,
              height,
            }}
          >
            content
          </div>
        )}
      </AutoSizer>
    </div>
  );
};
```

## 🧩 Business scene
Now most business scenarios need to be compatible with big data, such as **big data table, big data tree, big data drop-down box**, etc., and all big data components need to specify **width and height**, Most of the actual business interface needs to calculate the width and height in real time, and **react-auto-sizer** is to complete the task of **automatic calculation of width and height**.

![visiblearea](https://raw.githubusercontent.com/niexq/picbed/main/picgo/visiblearea.png)

## 🧑‍💻 Coding
At the beginning of the pre-research, **windows** was bound to **resize**, but due to **resize**, there will be performance problems when the window changes, and some extreme pixels will appear jitter. ;

ResizeObserver, the interface can listen to changes in the content area of **Element** or the bounding box of **SVGElement**. The content area needs to be subtracted from the padding. -- from MDN

**ResizeObserver** best choice， use **react hook useEffect**，The core code is as follows：

```js

const updateState = useCallback(
    (newWidth: number, newHeight: number, entry: ResizeObserverEntry) => {
      // update state
      // onResize width, height
      props.onResize({ width: newWidth, height: newHeight }, entry);
    },
    [childParams, disableHeight, disableWidth, onResize],
  );

const observer = useMemo(
    () =>
      new ResizeObserver((entries: ResizeObserverEntry[]) => {
        for (const entry of entries) {
          const contentRect = entry.contentRect;
          const width = Math.trunc(contentRect?.width || 0);
          const height = Math.trunc(contentRect?.height || 0);
          updateState(width, height, entry);
        }
      }),
    [updateState],
  );
  
useEffect(() => {
    if (!_autoSizerRef?.current?.parentNode) {
      throw new Error('Not Found AutoSizer parentNode');
    }
    observer.observe(_autoSizerRef?.current?.parentNode as Element);
    return () => {
      observer.disconnect();
    };
  }, [observer]);
```

Focus：

**observer.observe(_autoSizerRef?.current?.parentNode as Element)**,listen **parent dom node**

**contentRect**: [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry) return a [`DOMRectReadOnly`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRectReadOnly) read-only property `contentRect`， object containing the new size of the observed element, property：

```json
{
  "x": 0,
  "y": 0,
  "width": 300,
  "height": 200,
  "top": 0,
  "right": 300,
  "bottom": 200,
  "left": 0
}
```
contentRect returns the content box, which is the size of the content area (for detailed reasons, please refer to Zhang Xinxu's introduction to ResizeObserver)

![content-box](https://raw.githubusercontent.com/niexq/picbed/main/picgo/content-box.png)

so **contentRect.width** 、**contentRect.height** is the width and height we need


## ⭐️ Thanks for reading

github：https://github.com/niexq/react-auto-sizer,  Thanks for reading and welcome **Star**


## 🐳 Source of inspiration

[react-virtualized-auto-sizer](https://github.com/bvaughn/react-virtualized-auto-sizer)<br />
[ResizeObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver)<br /> 
[Detect DOM size changes JS API ResizeObserver](https://www.zhangxinxu.com/wordpress/2020/03/dom-resize-api-resizeobserver/)