Say Goodbye to useEffect and useState in React
In React, managing data fetching can often lead to complex code structures, especially when using useEffect and useState. This approach, while functional, can result in verbose and repetitive code, often referred to as "state management hell."
@tanstack/react-query is a powerful data-fetching library for React that simplifies asynchronous operations. It provides tools for fetching, caching, synchronizing, and updating server state in your applications. With features like automatic caching, background updates, and built-in support for retries and error handling, it enhances efficiency and code readability, making it an essential tool for modern React development.
useQuery
import { useEffect, useState } from 'react';
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('/posts');
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
};
fetchData();
}, []);
import { useQuery } from '@tanstack/react-query';
const fetchData = async () => {
const response = await fetch('/posts');
return response.json();
};
const { data, error, isLoading } = useQuery(['posts'], fetchData);
Traditional Approach: useEffect
and useState
- Complexity: Requires multiple state variables (data, isLoading, error).
- Boilerplate: Involves extensive setup for fetching, error handling, and loading states.
- No Caching: Each fetch call is independent, with no built-in caching mechanism.
Optimized Approach: useQuery
from TanStack Query
- Simplicity: Consolidates state management into a single hook.
- Automatic Caching: Provides built-in caching, reducing redundant network requests.
- Cleaner Code: Significantly reduces lines of code and improves readability.
useMutation
import { useState } from 'react';
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(null);
const [isSuccess, setIsSuccess] = useState(false);
const handleUpdate = async () => {
setIsLoading(true);
setIsError(null);
setIsSuccess(false);
try {
const response = await fetch('/posts/1', {
method: 'PUT',
body: JSON.stringify({ title: 'Updated Title' }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
await response.json();
setIsSuccess(true);
} catch (error) {
setIsError(error);
} finally {
setIsLoading(false);
}
};
import { useMutation } from '@tanstack/react-query';
const updateData = async (newData) => {
const response = await fetch('/posts/1', {
method: 'PUT',
body: JSON.stringify(newData),
});
return response.json();
};
const mutation = useMutation(updateData);
const handleUpdate = () => {
mutation.mutate({ title: 'Updated Title' });
};
const { isLoading, isError, isSuccess } = mutation;
Efficient Approach: useMutation
- Streamlined Process: Encapsulates mutation logic, reducing boilerplate.
- Built-in State Management: Automatically tracks loading, error, and success states.
- Cleaner Code: Enhances readability and maintainability with fewer lines.
Traditional Approach: Manual State Management
- Verbose Setup: Requires multiple
useState
hooks to track mutation states. - Complex Logic: Involves detailed error handling and state updates.
- Increased Complexity: Leads to more lines of code and potential for errors.
You can join the newsletter to be notified of awesome interactive articles and courses about software, design and AI. You will receive at most a few emails per month.