javascriptreactjsdom-eventsrefcreate-ref

How to access more than one element of Dom in react using React.createRef()


I know how to access single element of dom using React.createRef().But I want to access two different element using createRef. I have seen some example on stackoverflow for accessing multiple elements dynamically but unable to understand.I am attaching here my simple code where I want to change the background color of span tag onClick of button. I followed this by react Docs. Can someone please guide me, what I am doing wrong here.

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
    // this.myRef = React.createRef();
    this.textInput = null;

    this.state = {
      fname:""
    }
  }

  setTextInputRef = element => {
    console.log("element",element);
    this.textInput = element;
  };

green = () =>{
  console.log("green ",this.textInput);
  /*   this.textInput.current.style.backgroundColor = "green"; */
  this.textInput.style.backgroundColor = "green";
}

red = () =>{
  console.log("red ",this.textInput);
  /*   this.textInput.current.style.backgroundColor = "red"; */
  this.textInput.style.backgroundColor = "red";
}

  render() {
    return (
      <div>
      {/* 
      <span id="green" ref={input => { this.setTextInputRef = input; }}>Green</span><br/>
      <span id="red" ref={input => { this.setTextInputRef = input; }}>Red</span><br/> 
      */}
      <span id="green" ref={this.setTextInputRef}>Green</span><br/>
      <span id="red" ref={this.setTextInputRef}>Red</span><br/>
      <button onClick={this.green}>For Green</button><br/>
      <button onClick={this.red}>For Red</button><br/>
      </div>
    )
  }
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))

In above code If user click on btn than respective span color should be change.

Any help will be appreciated.

here is jsfiddle for more info


Solution

  • You can create multiple refs within your constructor if the elements rendered are static and access the elements using this.myRef.current

    Your code with createRef would look like below

    import React from "react";
    import "./styles.css";
    
    export default class TodoApp extends React.Component {
      constructor(props) {
        super(props);
        this.greenInputRef = React.createRef();
        this.redInputRef = React.createRef();
        this.state = {
          fname: ""
        };
      }
    
      green = () => {
        console.log("green ", this.textInput);
        /*   this.textInput.current.style.backgroundColor = "green"; */
        this.greenInputRef.current.style.backgroundColor = "green";
      };
    
      red = () => {
        console.log("red ", this.textInput);
        /*   this.textInput.current.style.backgroundColor = "red"; */
        this.redInputRef.current.style.backgroundColor = "red";
      };
    
      render() {
        return (
          <div>
            {/* 
          <span id="green" ref={input => { this.setTextInputRef = input; }}>Green</span><br/>
          <span id="red" ref={input => { this.setTextInputRef = input; }}>Red</span><br/> 
          */}
            <span id="green" ref={this.greenInputRef}>
              Green
            </span>
            <br />
            <span id="red" ref={this.redInputRef}>
              Red
            </span>
            <br />
            <button onClick={this.green}>For Green</button>
            <br />
            <button onClick={this.red}>For Red</button>
            <br />
          </div>
        );
      }
    }
    

    Working Demo

    If you are rendering code snippet dynamically by looping over it, you can create ref in the below manner

    constructor(props) {
       super(props);
    
       props.data.forEach(item => {
          this[`dataRef${item.id}] = React.createRef();
       })
    }  
    
    ...
    render() {
       return (
           <div>
            {
               data.map(item => 
                  <p ref={this[`dataRef{item.id}]}>{item.name}</p>
               )
             }
           </div>
       )
    }