I’m working on a Next.js project where I have a component that fetches data using axios
and the useEffect
hook. The data is fetched based on the router.query
object to enable dynamic routing. However, I’m facing an issue where changing the link doesn’t update the fetched data, and it returns the old data from the previous router.query
.
Here’s a simplified version of my code:
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import axios from 'axios';
const MyComponent = () => {
const router = useRouter();
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(`/api/data/${router.query.id}`);
setData(response.data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
return () => {
// Optional cleanup function if needed
};
}, [router.query]);
return (
<div>
{/* Render data here */}
</div>
);
};
export default MyComponent;
In an attempt to resolve the issue, I tried using AbortController to cancel the previous fetch when the useEffect runs with the new router.query values. However, this approach didn’t seem to solve the problem, and I’m still getting outdated data from the previous query.
Here is the attempted code:
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import axios from 'axios';
const MyComponent = () => {
const router = useRouter();
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const abortController = new AbortController();
try {
const response = await axios.get(`/api/data/${router.query.id}`, {
signal: abortController.signal,
});
setData(response.data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Error fetching data:', error);
}
}
};
fetchData();
return () => {
abortController.abort();
};
}, [router.query]);
return (
<div>
{/* Render data here */}
</div>
);
};
export default MyComponent;
2
Answers
I think the issue you are facing is that when the route changes, the
useEffect
runs again but the new data is not immediately available (as it needs to be loaded first). Therefore, that first re-render triggered by the route change still has the previous data in thedata
state.I would keep the
AbortController
(as it can be useful if you navigate across multiple pages too fast for any request to finish), but you should also reset thedata
state before requesting the new data:Try this way