Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS componentDidMount + render

I am currently using react to create d3 visualizations. I'm a little confused about the relationship between the render and componenetDidMount methods (is methods the proper term?). Here is what I have (I excluded some code for simplicity):

var Chart = React.createClass({
  componentDidMount: function () {
    var el = this.getDOMNode();
    console.log(el);
    d3Chart.create(el, {
        width: '500',
        height: '300'
    }, this.getChartState(),this.getAccessState);
  },

  render: function () {
    return (
        <div className="row pushdown">
                <div className="d3-block">
                    <div className="Chart" />
                </div>
        </div>
    );
  }
}

On line 3, el gets assigned this.getDOMNode(); which always points to the top level element in the render function (div "row pushdown"). So does this.getDOMNode() always refer to the top level element in the render function? What I'm actually trying to do is render the d3 chart within the innermost div (.Chart). I first tried doing this.getDOMNode().find('.Chart') but that didn't work.

First question: I know that I shouldn't be trying to touch the real DOM here but how would I go about selecting something further down on the VirtualDOM?

Second question: I know that, given I am very new to this, am probably doing this the wrong way. Can you suggest a better method here?

Third question: I want to add a chart legend in a sibling div of ".Chart". Should I be creating a new component for this? Or in my d3Chart can I use selectors to do this?

Thank you in advance for your help!

P.S. I have one side question:

I've seen people use React.render(<Chart />,document.body) instead of using React.createElement within that. Could somebody explain to me the difference?

like image 373
Jarryd Goodman Avatar asked Dec 25 '22 22:12

Jarryd Goodman


2 Answers

Yes, getDOMNode() returns the outermost DOM element that was rendered.

A1. I'd suggest you use a ref attribute (documentation) which provides a reference to the DOM element for later usage:

<div ref="chart" className="Chart" />

componentDidMount: function() {
    // << you can get access to the element by name as shown below
    var chart = this.refs.chart; 
    // do what you want here ...
}

A2. While ultimately you might want to refactor your code into multiple components, there's nothing wrong with what you've created (assuming you try the ref option mentioned above).

A3. As the legend would represent a very different piece of functionality (and isolated), creating a distinct component would be typical React. You might still have a Chart component that contains both the actual chart visualization but also has another component which displays a legend. It's a nice separation of concerns. But, you could also consider a Flux model where each component listens for changes and renders its visuals completely independently. If they work tightly together, a Flux model may not make as much sense.

Side: Using JSX, you might see:

React.render(<App />, document.body)

That would just render the App into the document body contents.

That is equivalent to precompiled JSX:

React.render(React.createElement(App, null), document.body);
like image 163
WiredPrairie Avatar answered Dec 28 '22 09:12

WiredPrairie


Just a note...as of v0.13. componentDidMount() may not yet have this.refs available. From the changelog:

ref resolution order has changed slightly such that a ref to a component is available immediately after its componentDidMount method is called; this change should be observable only if your component calls a parent component's callback within your componentDidMount, which is an anti-pattern and should be avoided regardless

like image 27
GAEfan Avatar answered Dec 28 '22 09:12

GAEfan