Let’s build an input box that outputs its contents in real-time. This gives us a chance to review React events and state.

To start, create a new React app called realtime-input using create-react-app.

$ npx create-react-app realtime-input
$ cd realtime-input
$ npm start

Open your web browser to http://localhost:3000/ to see the standard React welcome page.

Input

The first step is to create an input box within our render function. We can also add above it a section for the eventual name input.

// src/App.js
import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div>
        <p>Updated name: </p>
        <p>Change name:</p>
        <input type="text" />
      </div>
    );
  }
}

export default App;

Input

Events

React ships with a number of synthetic events that work across all browsers. One of these is onChange which will capture any changes to our input box. Let’s tell it to log “Hi” to the dev console once clicked.

// src/App.js
import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div>
        <p>Updated name: </p>
        <p>Change name:</p>
        <input type="text" onChange={console.log('hi')}/>
      </div>
    );
  }
}

export default App;

If you look at the webpage you can see that “Hi” is logged even before we type anything.

Console

That’s not what we want. The reason is that when render is fired everything within it is called. Since we don’t want this action to happen until after the button is clicked we need to pass in an arrow function instead.

// src/App.js
<input type="text" onChange={() => console.log('Hi')} />

Now if you revisit the page there is nothing in the console until you start typing within the input box.

State

We need somewhere to store our input which is where setState comes in. We can set an initial state at the top of our app and give a default value to name which will hold the result of the input box.

Then we can capture the onChange event object and pass it as the variable e to our arrow function. By using e.target.value we obtain the value of the input box itself.

Finally we can output the name using our state as {this.state.name}.

// src/App.js
import React, { Component } from 'react';

class App extends Component {
  state = {
    name: ''
  };
  render() {
    return (
      <div>
        <p>Updated name: {this.state.name}</p>
        <p>Change name:</p>
        <input
          type="text"
          onChange={e => {
            this.setState({
              name: e.target.value
            });
          }}
        />
      </div>
    );
  }
}

export default App;

If you look at the webpage again you’ll find that typing in text has it outputted next to “Updated name: “ as desired.

State

Controlled Components

There’s one final step we should make. React components control their own state, but HTML forms like <input> by default have their own state, too. We should explicitly set the <input> state to match the state of our React component, which we can do by setting a value for it.

// src/App.js
...
<input
  type="text"
  value={this.state.username} // new!
  onChange={e => {
    this.setState({
      name: e.target.value
    });
  }}
/>
...

And we’re done.

Conclusion

In this basic example we created an HTML input, captured its value via an event object, and transmitted that value into the state of the App component.