javascriptreactjsdomreact-dom

Should I use ref or findDOMNode to get react root dom node of an element?


I'm on a situation where I want to make some dom-node size calculations (top, bottom and size properties of the rendered DOM node)

What I'm doing right now, on the componentDidUpdate method is to call findDOMNode on this:

 componentDidUpdate() {
        var node = ReactDOM.findDOMNode(this);

        this.elementBox = node.getBoundingClientRect();
        this.elementHeight = node.clientHeight;
        // Make calculations and stuff
}

This is working fine, but I'm a bit worried about performance, and react best practices. Several places talks about using ref property instead of findDOMNode, but all of them are for child dom elements, on my case I only want the root DOM node of my component.

The alternative using ref may look like this:

render(){
   return (
            <section // container
                ref={(n) => this.node = n}>
                 // Stuff
            </section>
}
 componentDidUpdate() {

        this.elementBox = this.node.getBoundingClientRect();
        this.elementHeight = this.node.clientHeight;
        // Make calculations and stuff
}

To be honest, attaching a ref callback to my root dom node just to get it's reference does not feel correct to me.

What is considered the best practice on this case ? Which one has better performance ?


Solution

  • Here is how we can do that in modern react. Since findDOMNode is already deprecated in react 18, this is how we should do it according to the API documentation.

    Reference: https://react.dev/reference/react-dom/findDOMNode#alternatives

    Class components:

     constructor(props) {
        super(props);
        this.nodeRef = React.createRef(); // Create a ref
      }
    
      componentDidUpdate() {
        const node = this.nodeRef.current;
        this.elementBox = node.getBoundingClientRect();
        this.elementHeight = node.clientHeight;
        // Make calculations and stuff
      }
    
      render() {
        return (
          <section ref={this.nodeRef} >
    

    Functional components:

      const nodeRef = useRef(null);
      const [elementBox, setElementBox] = useState(null);
      const [elementHeight, setElementHeight] = useState(0);
    
      useEffect(() => {
        if (nodeRef.current) {
          const node = nodeRef.current;
          setElementBox(node.getBoundingClientRect());
          setElementHeight(node.clientHeight);
          // Make calculations and stuff
        }
      }, [/* dependencies */]);
    
      return (
        <section ref={nodeRef} >