19

I'm writing a component decorator that is able to detect when a DOM element's size is altered (by css, javascript, window resize etc).

It already works perfectly, I'm now trying to make its API easy to use, so, what's easier than this?

class Foobar extends React.Component {
  render() {
    return <div onResize={() => console.log('resized!')}>Foobar</div>;
  }
}
ReactDOM.render(resizeAware(Foobar), app);

The problem I'm facing, is that the onResize event is not being triggered when I trigger it...

These are two attempts to trigger the event:

// method 1
onResize() {
  const resizeEvent = document.createEvent('HTMLEvents');
  resizeEvent.initEvent('resize', true, true);
  console.log('triggering resize...');
  findDOMNode(this.componentNode).dispatchEvent(resizeEvent);
}

// method 2
onResize() {
    console.log('triggering resize...');
    findDOMNode(this.componentNode).dispatchEvent(new Event('resize'));
}

If I listen for the event with:

findDOMNode(this).addEventListener('resize', () => console.log('resized'));

Everything works. So it seems like the event I'm dispatching is received by the real DOM element and not by the virtual DOM.

The question now is, why the onResize callback is not called?
If there's not a solution, how would you make my decorator API available?

NB: I don't want a way to detect the resize of the component, I just need to dispatch an event to React and make it accessible with onResize

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Fez Vrasta
  • 14,110
  • 21
  • 98
  • 160
  • Check out [`react-sizeme`](https://github.com/ctrlplusb/react-sizeme). Disclaimer: I am the author. :-) – ctrlplusb Jun 12 '16 at 16:45
  • I've already a resize event working (it doesn't use any timer internally) https://github.com/FezVrasta/react-resize-aware I just want to improve its API – Fez Vrasta Jun 12 '16 at 16:58

2 Answers2

8

Another NPM lib to listen to resize event of a div. Check the demo

matt
  • 1,046
  • 1
  • 13
  • 26
  • This package really helped me – Nima habibkhoda Oct 21 '19 at 06:57
  • Thanks! Your answer helped me find the best package for me : [React Resize Observer](https://www.npmjs.com/package/rc-resize-observer), lighter and same approach. Only, when using multiple instances, React Resize Detector keep rendering indefinitely the last Component that wrapped ChartJS graph. React Resize Observer handle this perfectly for me. – KeitelDOG Jul 13 '20 at 17:51
3

I used this post and simply convert that to a React component. All you need to do is to define a MutationObserver in componentDidMount so it can watch for resize

class ResizableDiv extends React.Component {
    constructor(props) {
        super(props);
        this.ref = React.createRef();
    }
    
    componentDidMount() {
        const element = this.ref.current;
        element.addEventListener('resize', (event) => console.log(event.detail));
        function checkResize(mutations) {
            const el = mutations[0].target;
            const w = el.clientWidth;
            const h = el.clientHeight;

            const isChange = mutations
                .map((m) => `${m.oldValue}`)
                .some((prev) => prev.indexOf(`width: ${w}px`) === -1 || prev.indexOf(`height: ${h}px`) === -1);

            if (!isChange) { return; }
            const event = new CustomEvent('resize', { detail: { width: w, height: h } });
            el.dispatchEvent(event);
        }
        const observer = new MutationObserver(checkResize);
        observer.observe(element, { attributes: true, attributeOldValue: true, attributeFilter: ['style'] });
    }
    
    
    render() {
      return ( <div ref={this.ref} className='drag'> Resize me! < /div>);
      }
    }

    ReactDOM.render( < ResizableDiv / > ,
      document.getElementById('root')
    );
.drag {
  border: 1px solid red;
  width: 200px;
  height: 100px;
  resize: both;
  overflow: hidden;
}
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root" />
Hamed
  • 1,351
  • 9
  • 23