sagi
sagi

Reputation: 5737

React.js is losing focus with controlled form input

I'm trying to follow the Handling Multiple Inputs example from: https://facebook.github.io/react/docs/forms.html#handling-multiple-inputs

I tried to add two form elements, firstName and lastName. One is rendered within the main render() function, whereas the other is created using a separate JSX function called LastName().

The result is available here: https://codepen.io/sagiba/pen/Kmdrdz?editors=0010

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2,
      firstName: 'John',
      lastName: 'Doe'
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    const LastName = () => {
      return (
        <label>
          Last Name:
          <input
            name="lastName"
            type="text"
            value={this.state.lastName}
            onChange={this.handleInputChange} />
        </label>
      );
    };
    
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          First Name:
          <input
            name="firstName"
            type="text"
            value={this.state.firstName}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <LastName />
      </form>
    );
  }
}

ReactDOM.render(
  <Reservation />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Both are rendered as expected. However when trying to edit the value of last name the component is losing focus on every keystroke. This doesn't happen with firstName.

What am I doing wrong?

Upvotes: 4

Views: 3607

Answers (2)

Pale Blue Dot
Pale Blue Dot

Reputation: 57

Good question!
The reason LastName loses focus is that the component is nested, so it is redefined for each parent component rendering, react consider they are different components, and would reset its state, destroy related DOM and create everything from scrach. In the end, there is no place to keep the foucs.
For more detail and exact info, I would recommend you read the official greate document: https://react.dev/learn/preserving-and-resetting-state#different-components-at-the-same-position-reset-state

Upvotes: 0

rjerue
rjerue

Reputation: 168

React will rerender the application each time there is a change in state. Because of this, it runs the function to recreate your last name component; the function returns something "new" everytime. Just remove it from the function and you'll be golden.

render() { 
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          First Name:
          <input
            name="firstName"
            type="text"
            value={this.state.firstName}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Last Name:
          <input
            name="lastName"
            type="text"
            value={this.state.lastName}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

Upvotes: 3

Related Questions