Managing Async Calls in React with useEffect
Handling asynchronous operations, such as fetching data from an API, is a common requirement in React applications. The useEffect
hook is a powerful tool for managing these async operations effectively. This article provides examples of how to handle async calls using useEffect
in React.
Understanding useEffect
The useEffect
hook allows you to perform side effects in functional components, such as data fetching, subscriptions, or manual DOM manipulations. It runs after the render and can be configured to run under specific conditions by using dependencies.
Example 1: Fetching Data with useEffect
The following example demonstrates how to fetch data from an API using useEffect
:
import React, { useState, useEffect } from 'react';
function FetchData() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
return (
Data Fetch Example
{loading ? Loading...
: (
Title: {data?.title}
Body: {data?.body}
)}
);
}
export default FetchData;
Example 2: Handling Async Cleanup
Sometimes, async operations need to be canceled if a component unmounts or a dependency changes. The following example demonstrates cleanup in useEffect
:
import React, { useState, useEffect } from 'react';
function FetchWithCleanup() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const result = await response.json();
if (isMounted) {
setData(result);
}
} catch (error) {
console.error('Error fetching data:', error);
} finally {
if (isMounted) {
setLoading(false);
}
}
};
fetchData();
return () => {
isMounted = false;
};
}, []);
return (
Async Cleanup Example
{loading ? Loading...
: (
Title: {data?.title}
Body: {data?.body}
)}
);
}
export default FetchWithCleanup;
Example 3: Using Dependencies in useEffect
By providing a dependency array to useEffect
, you can control when the effect runs. The following example demonstrates how to refetch data based on a dependency:
import React, { useState, useEffect } from 'react';
function FetchWithDependency() {
const [postId, setPostId] = useState(1);
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(\`https://jsonplaceholder.typicode.com/posts/\${postId}\`);
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, [postId]);
return (
Dependency Example
{data && (
Title: {data.title}
Body: {data.body}
)}
);
}
export default FetchWithDependency;
Best Practices
- Always handle errors in async calls to avoid crashes.
- Use cleanup functions to cancel ongoing async operations when the component unmounts.
- Use dependencies wisely to avoid unnecessary re-renders or missed updates.
By managing async calls effectively with useEffect
, you can create more robust and user-friendly React applications.