ReactJS componentDidMount + render

匿名 (未验证) 提交于 2019-12-03 03:03:02

问题:

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?

回答1:

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); 


回答2:

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



回答3:

this.refs is perfect to find any dom node in react component life cycle using ReactDOM library. Install react-dom with NPM or include the JS in your page.

So your entire component code should look like this:

import React from 'react'; import ReactDOM from 'react-dom';  var Chart = React.createClass({   componentDidMount: function () {     var el = ReactDOM.findDOMNode(this.refs.chartComp);     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 ref="chartComp" className="Chart" />                 </div>         </div>     );   } } 


回答4:

Please note that as of React v15.0 getDOMNode() is removed (deprecated since v0.13) and can no longer be used.

edit: There's a thorough explanation about deprecation of getDOMNode() and introduction of React.findDOMNode(component) (that you should use instead) in the following answer: https://stackoverflow.com/a/30191683/6223301



回答5:

rendering go from parent to childrem. So componentDidMount may not have refs to child nodes instead put setTimeout function so all child node got rendered and refs will be available for actions



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!