tius
tius

Reputation: 550

focus() doesn't set on input field after displaing (use refs)

Dumb React question: how to set focus on input after it displayed and why my code doesn't work? (Without display toggle it works.)

edit: What I expect: after click on a button, the input field appears (by removing .dnone class) and get a focus on it. (But it doesn't.)

My code:

import "./styles.css"; // with .dnone class with display:none
import React from 'react';

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.input = React.createRef();
    this.state = {
      active: false
    }
  }

  click = (e) => {
    e.preventDefault();
    this.setState({
      active: true
    });
    this.input.current.focus();
  }

  render () {
    return (
      <div className="App">
        <input type="text" ref={this.input} className={(this.state.active ? "" : "dnone")} />
        <button type="button" onClick={(e) => this.click(e)}>click</button>
      </div>
    );
  }
}

live demo: https://codesandbox.io/s/immutable-sea-9884z?file=/src/App.js:0-607

Thank you!

Upvotes: 3

Views: 3638

Answers (1)

Drew Reese
Drew Reese

Reputation: 203062

The issue is that React state updates are asynchronously processed, so in the click handler when you enqueue a state update you are immediately attempting to focus on the input, but since the active state hasn't updated yet you can't, the dnone classname hasn't been removed and input made visible yet.

Move the focus logic into the componentDidUpdate lifecycle method to "respond" to the active state updating.

componentDidUpdate(prevProps, prevState) {
  if (prevState.active !== this.state.active && this.state.active) {
    this.input.current.focus();
  }
}

click = (e) => {
  e.preventDefault();
  this.setState({
    active: true
  });
}

Edit focus-doesnt-set-on-input-field-after-displaing-use-refs

Upvotes: 2

Related Questions