The Fetch API is a built-in browser interface used to make HTTP requests to servers. In React, the Fetch API is commonly used to retrieve or send data from/to an API.
Basics of Fetch API
The fetch() function is used to make HTTP requests. It returns a Promise that resolves to the Response object.
Syntax
fetch(url, options)
.then(response => response.json())
.then(data => {
// Handle data
})
.catch(error => {
// Handle errors
});
Using Fetch API in React
1. Fetching Data (GET Request)
Fetch data from a REST API when the component renders.
import React, { useState, useEffect } from 'react';
const App = () => {
const [data, setData] = useState(null); // State for storing fetched data
const [loading, setLoading] = useState(true); // Loading state
const [error, setError] = useState(null); // Error state
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => {
if (!response.ok) {
throw new Error('Failed to fetch data'); // Handle HTTP errors
}
return response.json(); // Parse JSON
})
.then((data) => {
setData(data); // Store data
setLoading(false); // Stop loading
})
.catch((error) => {
setError(error.message); // Handle errors
setLoading(false);
});
}, []); // Empty dependency array -> runs only on the first render
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h1>Posts</h1>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
};
export default App;
2. Sending Data (POST Request)
Send data to a server using POST.
import React, { useState } from 'react';
const App = () => {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [response, setResponse] = useState(null);
const handleSubmit = (e) => {
e.preventDefault();
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST', // Specify the HTTP method
headers: {
'Content-Type': 'application/json', // Set content type
},
body: JSON.stringify({
title,
body,
userId: 1, // Example payload
}),
})
.then((response) => response.json())
.then((data) => setResponse(data))
.catch((error) => console.error('Error:', error));
};
return (
<div>
<h1>Create Post</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
placeholder="Body"
value={body}
onChange={(e) => setBody(e.target.value)}
></textarea>
<button type="submit">Submit</button>
</form>
{response && (
<div>
<h2>Response</h2>
<p>Post created with ID: {response.id}</p>
</div>
)}
</div>
);
};
export default App;
3. Using Async/Await Syntax
Instead of .then chaining, you can use async/await for better readability.
import React, { useState, useEffect } from 'react';
const App = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error('Failed to fetch data');
}
const data = await response.json();
setData(data);
setLoading(false);
} catch (error) {
setError(error.message);
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h1>Posts</h1>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
};
export default App;
Error Handling
Always check if the response is okay (response.ok) to handle HTTP errors gracefully. Use .catch to handle network errors.
Common HTTP Methods
- GET: Retrieve data (e.g., fetch posts or users).
- POST: Create new data on the server (e.g., add a new user or post).
- PUT: Replace an existing resource.
- PATCH: Update parts of a resource.
- DELETE: Remove a resource.
Best Practices
- Use
try-catchwith Async/Await: Makes error handling cleaner. - Handle Loading State: Show loading spinners or messages while data is being fetched.
- Use Headers Properly: Set headers for APIs that require authentication (e.g., adding a token).
- Debounce Requests: When fetching on user input (like search), debounce the API calls to reduce unnecessary requests.
- Use a Custom Hook: Extract fetch logic into a reusable custom hook.
Advanced Topics
- Custom Hooks for Fetch: Reuse fetch logic.
- Error Boundaries: Catch errors in React components.
- Libraries like Axios: For better API handling with additional features (e.g., request cancellation).