ReactJS - Controlled Component



In controlled component, React provides a special attribute, value for all input elements and controls the input elements. The value attribute can be used to get and set the value of the input element. It has to be in sync with state of the component.

In other words, a React component that render.s a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a "controlled component".

Controlled component has to follow a specific process to do form programming.

Controlled Component With Single Input

Let us check the step by step process to be followed for a single input element.

Step 1 − Create a form element.

<input type="text" name="username" />

Step 2 − Create a state for input element.

this.state = { 
   username: '' 
}

Step 3 − Add a value attribute and assign the value from state.

<input type="text" name="username" value={this.state.username} />

Step 4 − Add a onChange attribute and assign a handler method.

<input type="text" name="username" value={this.state.username} onChange={this.handleUsernameChange} />

Step 5 − Write the handler method and update the state whenever the event is fired.

handleUsernameChange(e) {
   this.setState({
      username = e.target.value
   });
}

Step 6 − Bind the event handler in the constructor of the component.

this.handleUsernameChange = this.handleUsernameChange.bind(this)

Finally, get the input value using username from this.state during validation and submission.

handleSubmit(e) {
   e.preventDefault();
   alert(this.state.username);
}

Creating a Simple Form

Let us create a simple form to add expense entry using controller component in this chapter.

Step 1 − First, create a new react application, react-form-app using Create React App or Rollup bundler by following instruction in Creating a React application chapter.

Step 2 − Open the application in your favorite editor.

In the next step, create src folder under the root directory of the application.

Further to the above process, create components folder under src folder.

Step 3 − Create a file, ExpenseForm.css under src folder to style the component.

input[type=text], input[type=number], input[type=date], select {
   width: 100%;
   padding: 12px 20px;
   margin: 8px 0;
   display: inline-block;
   border: 1px solid #ccc;
   border-radius: 4px;
   box-sizing: border-box;
}
input[type=submit] {
   width: 100%;
   background-color: #4CAF50;
   color: white;
   padding: 14px 20px;
   margin: 8px 0;
   border: none;
   border-radius: 4px;
   cursor: pointer;
}
input[type=submit]:hover {
   background-color: #45a049;
}
input:focus {
   border: 1px solid #d9d5e0;
}
#expenseForm div {
   border-radius: 5px;
   background-color: #f2f2f2;
   padding: 20px;
}

Step 4 − Create a file, ExpenseForm.js under src/components folder and start editing.

Step 5 − Import React library.

import React from 'react';

Import ExpenseForm.css file.

import './ExpenseForm.css'

Step 6 − Create a class, ExpenseForm and call constructor with props.

class ExpenseForm extends React.Component {
   constructor(props) {
      super(props);
   }
}

Initialize the state of the component.

this.state = { 
   item: {} 
}

Create render() method and add a form with input fields to add expense items.

render() {
   return (
      <div id="expenseForm">
         <form>
            <label for="name">Title</label>
            <input type="text" id="name" name="name" placeholder="Enter expense title" />
            <label for="amount">Amount</label>
            <input type="number" id="amount" name="amount" placeholder="Enter expense amount" />
            <label for="date">Spend Date</label>
            <input type="date" id="date" name="date" placeholder="Enter date" />
            <label for="category">Category</label>
            <select id="category" name="category" 
              <option value="">Select</option>
              <option value="Food">Food</option>
              <option value="Entertainment">Entertainment</option>
              <option value="Academic">Academic</option>
            </select>
            <input type="submit" value="Submit" />
         </form>
      </div>
   )
}

Create event handler for all the input fields to update the expense detail in the state.

handleNameChange(e) {
   this.setState( (state, props) => {
      let item = state.item
      item.name = e.target.value;
      return { item: item }
   });
}
handleAmountChange(e) {
   this.setState( (state, props) => {
      let item = state.item
      item.amount = e.target.value;
      return { item: item }
   });
}
handleDateChange(e) {
   this.setState( (state, props) => {
      let item = state.item
      item.date = e.target.value;
      return { item: item }
   });
}
handleCategoryChange(e) {
   this.setState( (state, props) => {
      let item = state.item
      item.category = e.target.value;
      return { item: item }
   });
}

Bind the event handler in the constructor.

this.handleNameChange = this.handleNameChange.bind(this);
this.handleAmountChange = this.handleAmountChange.bind(this);
this.handleDateChange = this.handleDateChange.bind(this);
this.handleCategoryChange = this.handleCategoryChange.bind(this);

Next, add an event handler for the submit action.

onSubmit = (e) => {
   e.preventDefault();
   alert(JSON.stringify(this.state.item));
}

Attach the event handlers to the form.

render() {
   return (
      <div id="expenseForm">
         <form onSubmit={(e) => this.onSubmit(e)}>
            <label for="name">Title</label>
            <input type="text" id="name" name="name" placeholder="Enter expense title" 
               value={this.state.item.name}
               onChange={this.handleNameChange} />

            <label for="amount">Amount</label>
            <input type="number" id="amount" name="amount" placeholder="Enter expense amount"
               value={this.state.item.amount}
               onChange={this.handleAmountChange} />

            <label for="date">Spend Date</label>
            <input type="date" id="date" name="date" placeholder="Enter date" 
               value={this.state.item.date}
               onChange={this.handleDateChange} />

            <label for="category">Category</label>
            <select id="category" name="category"
               value={this.state.item.category}
               onChange={this.handleCategoryChange} >
              <option value="">Select</option>
              <option value="Food">Food</option>
              <option value="Entertainment">Entertainment</option>
              <option value="Academic">Academic</option>
            </select>

            <input type="submit" value="Submit" />
         </form>
      </div>
   )
}

Finally, export the component.

export default ExpenseForm

The complete code of the ExpenseForm component is as follows −

import React from 'react';
import './ExpenseForm.css'

class ExpenseForm extends React.Component {
   constructor(props) {
      super(props);
      this.state = {
         item: {}
      }
      this.handleNameChange = this.handleNameChange.bind(this);
      this.handleAmountChange = this.handleAmountChange.bind(this);
      this.handleDateChange = this.handleDateChange.bind(this);
      this.handleCategoryChange = this.handleCategoryChange.bind(this);
   }
   handleNameChange(e) {
      this.setState( (state, props) => {
         let item = state.item
         item.name = e.target.value;
         return { item: item }
      });
   }
   handleAmountChange(e) {
      this.setState( (state, props) => {
         let item = state.item
         item.amount = e.target.value;
         return { item: item }
      });
   }
   handleDateChange(e) {
      this.setState( (state, props) => {
         let item = state.item
         item.date = e.target.value;
         return { item: item }
      });
   }
   handleCategoryChange(e) {
      this.setState( (state, props) => {
         let item = state.item
         item.category = e.target.value;
         return { item: item }
      });
   }
   onSubmit = (e) => {
      e.preventDefault();
      alert(JSON.stringify(this.state.item));
   }
   render() {
      return (
         <div id="expenseForm">
           <form onSubmit={(e) => this.onSubmit(e)}>
            <label for="name">Title</label>
            <input type="text" id="name" name="name" placeholder="Enter expense title" 
               value={this.state.item.name}
               onChange={this.handleNameChange} />

            <label for="amount">Amount</label>
            <input type="number" id="amount" name="amount" placeholder="Enter expense amount"
               value={this.state.item.amount}
               onChange={this.handleAmountChange} />

            <label for="date">Spend Date</label>
            <input type="date" id="date" name="date" placeholder="Enter date" 
               value={this.state.item.date}
               onChange={this.handleDateChange} />

            <label for="category">Category</label>
            <select id="category" name="category"
               value={this.state.item.category}
               onChange={this.handleCategoryChange} >
              <option value="">Select</option>
              <option value="Food">Food</option>
              <option value="Entertainment">Entertainment</option>
              <option value="Academic">Academic</option>
            </select>
           
            <input type="submit" value="Submit" />
           </form>
         </div>
      )
   }
}
export default ExpenseForm;

index.js −

Next, create a file, index.js under the src folder and use ExpenseForm component.

import React from 'react';
import ReactDOM from 'react-dom';
import ExpenseForm from './components/ExpenseForm'

ReactDOM.render(
   <React.StrictMode>
      <ExpenseForm />
   </React.StrictMode>,
   document.getElementById('root')
);

index.html −

Finally, create a public folder under the root folder and create index.html file.

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <title>React App</title>
   </head>
   <body>
      <div id="root"></div>
      <script type="text/JavaScript" src="./index.js"></script>
   </body>
</html>

Serve the application using npm command.

npm start

Open the browser and enter http://localhost:3000 in the address bar and press enter.

Address Bar

Finally, enter a sample expense detail and click submit. The submitted data will be collected and showed in a pop-up message box.

Address Bars
Advertisements