How to deal with a ref within a loop?

You can use callback refs to generate and store the dynamic ref of each input in an array. Now you can refer to them using the index of the ref:

const Hello = React.forwardRef((props,  ref) => <input ref={ref} />);

class Button extends React.Component {
  onClick = () => this.props.onClick(this.props.id);

  render() {
    return (
      <button onClick={this.onClick}>{this.props.children}</button>
    );
  }
}

class TestRef extends React.Component {
  state = {
    data: [
      {
        name: "abc"
      },
      { name: "def" }
    ]
  };
  
  inputRefs = [];
  
  setRef = (ref) => {
    this.inputRefs.push(ref);
  };
  
  focusInput = (id) => this.inputRefs[id].focus();
  
  render() {
    return (
      <div>
        {this.state.data.map(({ name }) => (
          <Hello 
            placeholder={name} 
            ref={this.setRef} 
            key={name} />
        ))}
        <Button onClick={this.focusInput} id={0}>focus input 1</Button>
        <Button onClick={this.focusInput} id={1}>focus input 2</Button>
      </div>
    );
  }
}

ReactDOM.render(<TestRef />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

If the list wouldn’t be static, and items may be removed/replaced, you should probably use a WeakMap to hold the refs, or any other method of adding the ref by a constant id. You should also check before using the ref, because it might not exist:

const Hello = React.forwardRef((props,  ref) => <input ref={ref} />);

class Button extends React.Component {
  onClick = () => this.props.onClick(this.props.id);

  render() {
    return (
      <button onClick={this.onClick}>{this.props.children}</button>
    );
  }
}

class TestRef extends React.Component {
  state = {
    data: [{ name: "abc" }, { name: "def" }, { name: "ghi" }]
  };
  
  componentDidMount() {
    setTimeout(() => {
      this.setState(({ data }) => ({
        data: data.slice(0, -1)
      }))
    }, 3000);
  }
  
  inputRefs = new WeakMap;
  
  setRef = (id) => (ref) => {
    this.inputRefs.set(id, ref);
  };
  
  focusInput = (id) => {
    const input = this.inputRefs.get(id);
    
    if(input) input.focus(); // use only if the ref exists - use optional chaining ?. if possible instead
  }
  
  render() {
    const { data } = this.state;
  
    return (
      <div>
        {data.map(o => (
          <Hello 
            placeholder={o.name} 
            ref={this.setRef(o)} 
            key={o.name} />
        ))}
        
        <br />
        
        {data.map((o, i) => (
          <Button onClick={this.focusInput} id={o} key={o.name}>focus input {i + 1}</Button>
        ))}
      </div>
    );
  }
}

ReactDOM.render(<TestRef />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)