Controlled Component in React Forms
April 7, 2020
Form controls in React come in two types: Controlled Component and Uncontrolled Component. In this video, we will focus only on the Controlled Component.
In a Controlled Component, the “single source of truth” (data) is maintained in the React state
property. An input form element whose value is controlled by React in this way is called a “controlled component”.
In HTML, form elements such as <input>
, <textarea>
, and <select>
typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state
property of components, and only updated with setState()
.
In a Controlled Component, form data is handled by a React component using an event handler (e.g. handleChange
) for every state update. Since handleChange
runs on every keystroke to update the React state
, the displayed value will update as the user types. This makes it straightforward to modify or validate user input. The following example illustrates this explanation.
![](https://i0.wp.com/christianhur.com/wp-content/uploads/2020/04/react-form-controlled-component.png?fit=730%2C485&ssl=1)
Source code for demo in the video
import React from 'react'; //Parent component - contains main data class App extends React.Component { constructor(props) { super(props); this.state = { data: [] }; this.addData = this.addData.bind(this); } addData(newData){ let data = this.state.data; data.push(newData); this.setState({ data }); } render() { let data = this.state.data; return ( <div className="col-lg-12 text-center"> <h1>React Forms - Controlled Component</h1> <AddForm addData={this.addData} data={this.state.data}></AddForm> <hr></hr> <ul> {data.map( (e,i)=>{ return ( <li key={i}> {e.user} | {e.game} | {e.points} </li> ) }) } </ul> </div> ); } } // Child component - the Form to add one record // Controlled Component - source of truth in React class AddForm extends React.Component{ constructor(props){ super(props); this.state = { data : {user:'',game:'Galaga',points:0}} this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event){ let {name, value} = event.target; let data = this.state.data; data[name] = value; this.setState({data}) } error=false; handleSubmit(event){ //validate event.preventDefault(); if(!this.error){ this.props.addData(this.state.data); this.setState({ data : {user:'',game:'Galaga',points:0}}); } } render(){ let data = this.state.data; return( <div className="col-md-8 ml-5"> <form> <div className="form-row"> <div className="col-md-4 mb-3"> <label>User:</label> <input className="form-control" name="user" value={data.user} onChange={this.handleChange} /> </div> <div className="col-md-4 mb-3"> <label>Game:</label> <select className="form-control" name="game" defaultValue={data.game} onChange={this.handleChange} > <option>Pac-Man</option> <option>Pong</option> <option>Galaga</option> <option>Tetris</option> </select> </div> <div className="col-md-4 mb-3"> <label>Points:</label> <input className="form-control" name="points" type="number" min='0' max='10000' value={data.points} onChange={this.handleChange} /> </div> <div className="col-md-4 mb-3"> <button onClick={this.handleSubmit} className="btn btn-primary">Submit</button> </div> </div> </form> </div> ) } } export default App;