Use ResizeObserver to monitor the size of a single element

Keywords: TypeScript React Firefox

1, API introduction

ResizeObserver

This is an API that can monitor the size and position changes of an element. It is a class. It provides an observer, which will be called on each resize event. Currently, chrome, safari and fireFox(pc) are basically supported.

2, General usage

const resizeOb= new ResizeObserver(entries => {
    for(const entry of entries) {
        console.log(entry)
    }
})
resizeOb.observe(document.getElementById("test"))

//Print results
//{target: div#test, contentRect: DOMRectReadOnly}

By instantiating a listener and calling the observe method to import a DOM element or SVG element to be monitored, every time the resize event is triggered, the callback function that is introduced into the ResizeObserver instantiation will be executed. The callback function will return an array by default, which contains the elements and their readable information of each executed listener and the order of visiting elements. It is also the order in which listeners execute (yes, instantiate a listener, you can execute the observe method multiple times to listen to different elements!)

3, Use in react+typescript

If you simply listen to an element, you can call it as in the above example. However, if you want to use it with the help of react hooks and typescript, you need to pay more attention:

  • In hook, it still needs to be used in useEffect, because the observe method needs to pass in a valid DOM
  • In fact, the listener is also a side effect, which should be cancelled when the component is destroyed. For example, in useEffect, a function is returned to destroy the side effect
  • At present, the API is not recognized in typescript, at least in my version (3.7.5), I need to write my own declaration file.

Examples of use are as follows:

useEffect(() => {
       const resizeObserver = new ResizeObserver((entries) => {console.log(entries)});
        resizeObserver.observe(document.getElementById("test"))
        return (): void => { resizeObserver.unobserve(document.getElementById("test")) };
    }, []);

If it's a create react app scaffolding project, you need to add the statement of ResizeObserver in react app env.d.ts. If it's another typescript project, you need to declare it in global:

// Read only information about elements
interface DOMRectReadOnly {
    bottom:number;
    height:number;
    left:number;
    right:number;
    top:number;
    width:number;
    x:number;
    y:number;
}
//Parameter type in listener callback function, with its own element (target) and corresponding read-only location and size information (contentRect)
interface ResizeObserverEntry {
    target: HTMLElement | null;
    contentRect: ResizeObserverEntry["target"] extends null? null : DOMRectReadOnly
}
// The callback function that the listener constructor needs to pass in
type EntriesFuntion = (entries:Array<ResizeObserverEntry>)=>void;
/**
 * Element size and position change monitor
 */
declare class ResizeObserver {
    /**
     * Element size and position change monitor
     * @param entriesFn On the callback function attached to the listener
     * @returns {Observer} Returns a listener object
     */
    constructor(entriesFn:EntriesFuntion): ResizeObserver{};
    /**
     * Execute listening of target element
     * @param target Target element to listen on
     * @param options Set the box model of the element. The default is content box
     * @returns {void}
     */
    observe(target:HTMLElement|null,options?:{box:'border-box'|"content-box"}):void;

    /**
     * Cancel listening on the target element
     * @param target Target element to cancel listening
     * @returns {void}
     */
    unobserve(target:HTMLElement|null):void

    /**
     * Cancel listening for all elements
     */
    disconnect():void
}

4, Conclusion

ResizeObserver is called in the process of resize, and resize itself is a frequent trigger event. In the meantime, too much logic is actually a great influence on performance. If we want to perform a callback after changing certain element, we recommend collocation with function throttling.

Posted by mark_18 on Tue, 23 Jun 2020 00:43:40 -0700