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.

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.


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.