React, how to access the DOM element in my render function from the same component

47,840

Solution 1

Here, no need to use setTimeout. There are lifecycle methods for component, of which componentDidMount is called after the render. So, you can get the reference to your div in the method.

var TodoItem = React.createClass({
  ...
  componentDidMount: function () {
     if(this.myDiv) {
        this.myDiv.style.backgroundColor = "red";
     }
  }
  render:function(){
    return(
        <div className='name' ref = {c => this.myDiv = c}></div>
    );
});

Solution 2

You can use ReactDOM.findDOMNode(this) to access the underlying DOM node. But accessing the DOM node and manipulating like you do is against the React style of programming. It's better to use a state variable and called the setState method to re-render the DOM.

Solution 3

You can make use of ref callback to access the dom element in react, which is what React Docs recommend to follow

and do that in the componentDidMount lifecycle function as refs won't be accessible before the DOM is created

var TodoItem = React.createClass({
    ...
    componentDidMount() {
          setTimeout(function(){
               this.myDiv.style.backgroundColor = "red";
          )}, 1000);
    }
    render:function(){

        return(
            <div className='name' ref={(ele) => this.myDiv = ele}></div>
        )

})

DOCS

Solution 4

You should avoid accessing DOM element because the whole point of react is putting abstraction over dom. React keeps representation of DOM in memory which is referred as VirtualDom. Working with VirtualDom will make unit testing your application is easier.If you really know what you are doing, here is how to do it:

componentDidMount(){
const name=this.name.current.style() //current will return the actual DOM 
element
}
name=React.createRef()  //create a ref object

<div ref={this.name} className="anything" /> //your classname does not need to be named as "name". You access the element via the "ref" attribute not the classname.

In ComponentDidMount, when your component is mounted its style change will be applied.

Solution 5

Just came across this after trying to do form validation before opening a stripe checkout modal with React 14.

I would like to note that you're not actually accessing a DOM Element with references. You're simply accessing the React Component Object. Shown here:

enter image description here

The top one is calling ref.ticketForm, the bottom is showing document.getElementById('ticketform').

The reason I needed to do this was the following:

<Button color="success" size="lg" type="button" onClick={(e) => {
  const ticketForm = document.getElementById('ticketForm');
  const isValid = ticketForm.reportValidity();
  if (!isValid) e.stopPropagation();
}}>Buy Tickets</Button>

reportValidity() is a DOM Element method: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reportValidity

Referencing this issue, this person showed this method being used on a reference object, which naturally isn't correct: https://github.com/azmenak/react-stripe-checkout/issues/121#issuecomment-431635855

Hopefully this clears up that DOM Elements do not explicitly equal React Components. If you need to manipulate the DOM in any way, do it in a react way first. This is an edge case where I would rather rely on form validation for a dynamic form than manually doing very heavy custom validation.

Share:
47,840
wonghenry
Author by

wonghenry

front end engineer

Updated on January 11, 2022

Comments

  • wonghenry
    wonghenry over 2 years

    I'm wondering what's the best practice for accessing the DOM elements inside my render function from the same component. Note that I will be rendering this component multiple times on a page.

    e.g.

    var TodoItem = React.createClass({
        ...
        render:function(){
    
            function oneSecLater(){
                setTimeout(function(){
                //select the current className? this doesn't work, but it gives you an idea what I want.
                document.getElementsByClassName('name').style.backgroundColor = "red";
                    )}, 1000);
            }
    
            return(
                <div className='name'>{this.oneSecLater}</div>
            )
    
    
    
    })