Using async/await for cleaner asynchronous code in React
Using async/await with event handlers for cleaner code.
import { useState } from 'react';
function UserForm() {
const [username, setUsername] = useState('');
const [status, setStatus] = useState('idle');
const [userData, setUserData] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setStatus('loading');
try {
// Fetch user data
const response = await fetch(`https://api.github.com/users/${username}`);
if (!response.ok) {
throw new Error('User not found');
}
const data = await response.json();
setUserData(data);
setStatus('success');
} catch (error) {
console.error('Error fetching user:', error);
setStatus('error');
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="GitHub username"
required
/>
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Searching...' : 'Search'}
</button>
</form>
{status === 'error' && <p>Error: User not found</p>}
{status === 'success' && userData && (
<div>
<h2>{userData.name}</h2>
<p>Followers: {userData.followers}</p>
<p>Public repos: {userData.public_repos}</p>
</div>
)}
</div>
);
}Using async/await inside useEffect for data fetching.
import { useState, useEffect } from 'react';
function ProductList({ categoryId }) {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// Create an async function inside useEffect
const fetchProducts = async () => {
try {
setLoading(true);
const response = await fetch(
`https://api.example.com/products?category=${categoryId}`
);
if (!response.ok) {
throw new Error('Failed to fetch products');
}
const data = await response.json();
setItems(data);
setError(null);
} catch (error) {
setError(error.message);
setItems([]);
} finally {
setLoading(false);
}
};
// Call the async function
fetchProducts();
// Optional: cleanup function
return () => {
// Cancel any pending requests if needed
};
}, [categoryId]); // Re-run when categoryId changes
if (loading) return <div>Loading products...</div>;
if (error) return <div>Error: {error}</div>;
if (items.length === 0) return <div>No products found</div>;
return (
<div>
<h2>Products in category {categoryId}</h2>
<ul>
{items.map((item) => (
<li key={item.id}>{item.name} - ${item.price}</li>
))}
</ul>
</div>
);
}Making multiple API requests in parallel for better performance.
import { useState, useEffect } from 'react';
function Dashboard() {
const [userData, setUserData] = useState(null);
const [postsData, setPostsData] = useState([]);
const [commentsData, setCommentsData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchDashboardData = async () => {
try {
setLoading(true);
// Make all requests in parallel with Promise.all
const [userResponse, postsResponse, commentsResponse] = await Promise.all([
fetch('https://api.example.com/user'),
fetch('https://api.example.com/posts'),
fetch('https://api.example.com/comments')
]);
// Check if any request failed
if (!userResponse.ok || !postsResponse.ok || !commentsResponse.ok) {
throw new Error('One or more requests failed');
}
// Parse all responses in parallel
const [user, posts, comments] = await Promise.all([
userResponse.json(),
postsResponse.json(),
commentsResponse.json()
]);
// Update state with all data
setUserData(user);
setPostsData(posts);
setCommentsData(comments);
setError(null);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchDashboardData();
}, []);
if (loading) return <div>Loading dashboard data...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h1>Dashboard</h1>
{userData && (
<div>
<h2>Welcome, {userData.name}</h2>
</div>
)}
<div>
<h3>Recent Posts ({postsData.length})</h3>
<ul>
{postsData.slice(0, 5).map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
<div>
<h3>Recent Comments ({commentsData.length})</h3>
<ul>
{commentsData.slice(0, 5).map(comment => (
<li key={comment.id}>{comment.text}</li>
))}
</ul>
</div>
</div>
);
}Proper error handling with async/await for robust applications.
import { useState } from 'react';
function PaymentForm() {
const [cardNumber, setCardNumber] = useState('');
const [status, setStatus] = useState('idle');
const [errorMessage, setErrorMessage] = useState('');
const processPayment = async (paymentDetails) => {
const response = await fetch('https://api.example.com/payments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(paymentDetails),
});
if (!response.ok) {
// Handle different error status codes
if (response.status === 400) {
const errorData = await response.json();
throw new Error(errorData.message || 'Invalid payment details');
} else if (response.status === 401) {
throw new Error('Unauthorized. Please log in again.');
} else if (response.status === 429) {
throw new Error('Too many requests. Please try again later.');
} else {
throw new Error('Payment processing failed');
}
}
return response.json();
};
const handleSubmit = async (e) => {
e.preventDefault();
setStatus('processing');
setErrorMessage('');
try {
// Validate input
if (cardNumber.length < 16) {
throw new Error('Invalid card number');
}
// Process payment
const result = await processPayment({ cardNumber });
setStatus('success');
console.log('Payment successful:', result);
} catch (error) {
console.error('Payment error:', error);
setStatus('error');
setErrorMessage(error.message);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="card-number">Card Number:</label>
<input
id="card-number"
type="text"
value={cardNumber}
onChange={(e) => setCardNumber(e.target.value)}
placeholder="1234 5678 9012 3456"
/>
</div>
{status === 'error' && (
<div style={{ color: 'red' }}>{errorMessage}</div>
)}
<button
type="submit"
disabled={status === 'processing'}
>
{status === 'processing' ? 'Processing...' : 'Pay Now'}
</button>
{status === 'success' && (
<div style={{ color: 'green' }}>Payment successful!</div>
)}
</form>
);
}