Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react - accessing DOM without breaking encapsulation

Is there a cannonical way of going about doing something like the following without breaking encapsulation?

import React, { Component, PropTypes } from 'react';

class Dashboard extends Component {
    constructor(props, context) {
        super(props, context);

        this.setRef = ::this.setRef;
    }
    componentDidMount() {
        const node = ReactDOM.findDOMNode(this.someRef);
        const newHeight = window.innerHeight - node.offsetTop - 30;
        node.style.maxHeight = `${newHeight}px`;
    }

    render() {
        return (
            <div id="some-element-id" ref={this.setRef}>
            </div>
        );
    }

    setRef(ref) {
        this.someRef= ref;
    }
}

ReactDOM.findDOMNode seems to be the suggested way of going about this, but this still breaks encapsulation and the documentation has a big red flag to this extent.

like image 659
Jordan Avatar asked Apr 19 '16 20:04

Jordan


People also ask

How do you access the DOM element in React?

In React we can access the DOM element using Refs. Refs provide a way to access DOM nodes or React elements created in the render method. Creating Refs: Refs are created using React. createRef() and attached to React elements via the ref attribute.

Can I use createRef in functional component?

createRef can be used in both class and functional components.

Does React interact with DOM?

React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts.

Is React DOM deprecated?

Deprecations. react-dom : ReactDOM.render has been deprecated. Using it will warn and run your app in React 17 mode.


Video Answer


2 Answers

You should use the component "state" to set the style property of the react element, so you only access the "real" DOM node to calculate the height and then you update the state, re-rendering the component. The react component now has the same information as the real DOM node, so it shouldn't be breaking encapsulation.

Using vanilla JS to provide an example:

var Component = React.createClass({
    getInitialState: function(){
    return {
        style: {},
    }
  },
  componentDidMount: function(){
    var node = ReactDOM.findDOMNode(this);
    var newHeight = window.innerHeight - node.offsetTop - 30;
    this.setState({style: {backgroundColor: '#bbb', height: newHeight.toString() + 'px' }});
  },
  render: function(){
    return React.createElement('div', {style: this.state.style}, 'Height: ' + this.state.style.height);
  },
});

You can see it running in this fiddle.

like image 52
GonArrivi Avatar answered Oct 25 '22 23:10

GonArrivi


While this technically "breaks encapsulation" in the general sense, if there is no other way to do it (and in this case there is not), then using findDOMNode is your only choice and it is the correct one.

If you find yourself using it repeatedly, you should create a wrapper component to encapsulate that behavior.

like image 28
slessans Avatar answered Oct 26 '22 00:10

slessans