Skip to content

ReactJS - Forms

Handling forms is a fundamental part of web development. React provides a powerful way to manage form data using a concept called “controlled components”. This chapter explains how to create and manage forms in modern React using functional components and Hooks.

In HTML, form elements like <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, a controlled component is one where form data is handled by the React component’s state. The React state becomes the “single source of truth.”

This means:

  1. The value of the input element is driven by the React state.

  2. Any changes to the input (e.g., user typing) trigger an event handler that updates the React state.

Let’s create a simple form with a single text input. The value of this input will be stored in the component’s state, and any changes will update the state, re-rendering the component.

import React, { useState } from 'react';
function App() {
const [inputValue, setInputValue] = useState('Initial data...');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={handleChange}
/>
<h4>Current Value: {inputValue}</h4>
</div>
);
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

In this example:

  • useState('Initial data...') initializes our inputValue state with ‘Initial data…’.

  • The <input> element’s value prop is set to inputValue. This makes it a controlled component.

  • The onChange prop is set to the handleChange function. Whenever the user types in the input field, handleChange is called.

  • handleChange receives an event object, and event.target.value contains the current value of the input. It then calls setInputValue to update the state.

  • The <h4> tag displays the current inputValue, demonstrating that the state is updated in real-time.

When you type in the input field, the displayed text below it updates immediately. This is the essence of controlled components.

Sometimes, you might have form inputs or display elements in child components. You can manage the state in the parent component and pass down both the data and the update function as props.

import React, { useState } from 'react';
// Child component
function DataDisplayInput({ data, onDataChange }) {
return (
<div>
<input
type="text"
value={data}
onChange={onDataChange}
/>
<h3>Child Component Display: {data}</h3>
</div>
);
}
// Parent component
function App() {
const [appData, setAppData] = useState('Initial data...');
const handleAppDataChange = (event) => {
setAppData(event.target.value);
};
return (
<div>
<h2>Parent Component</h2>
<DataDisplayInput
data={appData}
onDataChange={handleAppDataChange}
/>
<h4>Parent Component Display: {appData}</h4>
</div>
);
}
export default App;

In this more complex example:

  • The App component (parent) holds the appData state and the handleAppDataChange function.

  • It renders the DataDisplayInput component (child), passing appData as the data prop and handleAppDataChange as the onDataChange prop.

  • The DataDisplayInput child component uses these props to control its input field and display the data.

  • When the input in DataDisplayInput changes, it calls this.props.onDataChange (which is handleAppDataChange from the parent), updating the state in the App component.

This pattern is known as “lifting state up”. While effective for simple cases, for deeply nested components or complex state interactions, consider using React’s Context API or state management libraries like Redux or Zustand. For more details on these advanced patterns, you can search for ‘React Context API’ or ‘React state management libraries’.

Benefits of Controlled Components:

  • Single Source of Truth: State is managed in one place, making debugging easier.

  • Validation: Input can be validated or transformed on the fly within the onChange handler.

  • Conditional Logic: Easily enable/disable submit buttons or show/hide form elements based on state.

Remember to handle other form elements like <textarea>, <select>, checkboxes, and radio buttons similarly, by controlling their value (or checked for checkboxes/radios) and using an onChange handler to update state.