Forms are a fundamental part of web applications, enabling users to input data that can be processed and stored.
React forms provide a dynamic and efficient way to gather user data by leveraging React’s state management and controlled components.
Understanding Controlled and Uncontrolled Components
In React, form components can be either controlled or uncontrolled. Knowing the difference between these types is essential to efficiently manage form data.
Controlled Components
In a controlled component, the form data is handled by the component’s state. Each form element (like an input field) has a corresponding piece of state that it updates when the user enters data.
Controlled components are the preferred way to manage forms in React, as they offer more control over form data and validation.
Example of a Controlled Component:
import React, { useState } from 'react';
function ControlledForm() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
alert(`Form submitted with input: ${inputValue}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Input:
<input type="text" value={inputValue} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledForm;
In this example:
- The inputValue state is controlled by handleChange.
- The form value is updated in real-time as the user types.
- When the form is submitted, the value of inputValue is used in the alert.
Uncontrolled Components
In uncontrolled components, the form data is managed by the DOM rather than the component’s state. This approach uses refs to access form values instead of binding them to a state variable.
Example of an Uncontrolled Component:
import React, { useRef } from 'react';
function UncontrolledForm() {
const inputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
alert(`Form submitted with input: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Input:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default UncontrolledForm;
In this example:
- inputRef is a reference to the input field.
- The value is accessed directly from the DOM using inputRef.current.value when the form is submitted.
Handling Events in Forms
Form elements in React trigger events such as onChange, onSubmit and onClick, allowing developers to create interactive forms by responding to user actions.
- onChange: Used to update the state as the user types into the input field.
- onSubmit: Called when the form is submitted, usually by clicking the “Submit” button or pressing Enter.
Example of Handling onChange and onSubmit Events:
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleUsernameChange = (e) => setUsername(e.target.value);
const handlePasswordChange = (e) => setPassword(e.target.value);
const handleSubmit = (e) => {
e.preventDefault();
alert(`Logging in with username: ${username} and password: ${password}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Username:
<input type="text" value={username} onChange={handleUsernameChange} />
</label>
<br />
<label>
Password:
<input type="password" value={password} onChange={handlePasswordChange} />
</label>
<br />
<button type="submit">Login</button>
</form>
);
}
In this example:
- Each input field updates its own state with onChange.
- handleSubmit uses e.preventDefault() to prevent page reload on form submission.
Form Validation
Validation is essential in forms to ensure the data entered by the user meets specific criteria. React allows you to implement custom validation logic and provide feedback based on the form’s state.
Example of Basic Form Validation:
function SignupForm() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const handleEmailChange = (e) => {
setEmail(e.target.value);
setError(validateEmail(e.target.value));
};
const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email) ? '' : 'Invalid email address';
};
const handleSubmit = (e) => {
e.preventDefault();
if (!error) {
alert(`Form submitted with email: ${email}`);
}
};
return (
<form onSubmit={handleSubmit}>
<label>
Email:
<input type="email" value={email} onChange={handleEmailChange} />
</label>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit" disabled={!!error}>Submit</button>
</form>
);
}
In this example:
- A regular expression checks the email format.
- If the email is invalid, an error message is displayed and the submit button is disabled.
Common Form Elements and Examples
React supports a variety of form elements, including text inputs, radio buttons, checkboxes and dropdowns.
Radio Buttons and Checkboxes
function PreferencesForm() {
const [language, setLanguage] = useState('JavaScript');
const [isSubscribed, setIsSubscribed] = useState(false);
const handleLanguageChange = (e) => setLanguage(e.target.value);
const handleSubscriptionChange = (e) => setIsSubscribed(e.target.checked);
return (
<form>
<label>
Preferred Language:
<input
type="radio"
value="JavaScript"
checked={language === 'JavaScript'}
onChange={handleLanguageChange}
/>
JavaScript
<input
type="radio"
value="Python"
checked={language === 'Python'}
onChange={handleLanguageChange}
/>
Python
</label>
<br />
<label>
Subscribe to newsletter:
<input type="checkbox" checked={isSubscribed} onChange={handleSubscriptionChange} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
In this example:
- checked manages the selected state for radio buttons and checkboxes.
Select Dropdowns
function DropdownForm() {
const [selection, setSelection] = useState('Option1');
return (
<form>
<label>
Choose an option:
<select value={selection} onChange={(e) => setSelection(e.target.value)}>
<option value="Option1">Option 1</option>
<option value="Option2">Option 2</option>
<option value="Option3">Option 3</option>
</select>
</label>
<button type="submit">Submit</button>
</form>
);
}
Form Submission and API Integration
Forms often require integration with APIs to submit data. This is done by using fetch or axios inside the handleSubmit function.
Example:
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
const result = await response.json();
console.log(result);
} catch (error) {
console.error('Error submitting form', error);
}
};