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-catch
with 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).