T
TanStack•14mo ago
eastern-cyan

Using navigate in useEffect leads to false routing

1. I navigate via a <Link> to the /about page. 2. The component of the /about page has a useEffect which executes navigate function. 3. The navigate only applies an id query param, not more. 4. Expect: I would expect the final path to be /about?id=1234 5. Actual: The router navigates back to the home route / I'm coming from and applies the id=1234 query param there instead. I created a repo with a reproduction and some additional notes in the README. Reproduction: https://github.com/lukaskoeller/tanstack-react-router-useEffect-navigate-reproduction I'm not sure if it's something I do wrong or rather a library bug, that's why I'm asking here first. Anybody that can help?
9 Replies
eastern-cyan
eastern-cyanOP•14mo ago
useEffect(() => {
console.log('useEffect')
setTimeout(() => {
void navigate({
search: (old) => ({
...old,
id: 'a1337b00c99',
}),
})
}, 1000);
}, [navigate]);
useEffect(() => {
console.log('useEffect')
setTimeout(() => {
void navigate({
search: (old) => ({
...old,
id: 'a1337b00c99',
}),
})
}, 1000);
}, [navigate]);
E.g. when I set a timeout, it is working as expected. So I would assume the useEffect just runs too early when the navigation in the lib is not yet done?
exotic-emerald
exotic-emerald•14mo ago
this most likely is a bug in router
exotic-emerald
exotic-emerald•14mo ago
GitHub
Release v1.45.5 · TanStack/router
Version 1.45.5 - 7/18/24, 6:52 PM Changes Fix react-router: use current matches for fromMatches and only build new matches when location overridden (#1968) (99f7352) by Christopher Horobin Test ...
exotic-emerald
exotic-emerald•14mo ago
can you please try it out ?
eastern-cyan
eastern-cyanOP•14mo ago
Yes this fixed it! Brillian. Thanks a lo @Manuel Schiller Heads up. A very similar problem happened in our production app again. This time, the router wouldn't navigate back to the "old" page but just wouldn't add the search params. See the affected code using v1.45.8 here:
useEffect(() => {
const firstRelation = (data?.relations ?? [])[0];

if (!searchId && firstRelation?.id) {
setTimeout(() => {
void navigate({
search: (old) => ({
...old,
searchId: firstRelation.id,
cityDep: firstRelation.departure.city,
cityArr: firstRelation.arrival.city,
countryDep: firstRelation.departure.country,
countryArr: firstRelation.arrival.country,
}),
params: true,
replace: true,
});
}, 500)
}
}, [data?.relations, firstSelected, navigate, searchId]);
useEffect(() => {
const firstRelation = (data?.relations ?? [])[0];

if (!searchId && firstRelation?.id) {
setTimeout(() => {
void navigate({
search: (old) => ({
...old,
searchId: firstRelation.id,
cityDep: firstRelation.departure.city,
cityArr: firstRelation.arrival.city,
countryDep: firstRelation.departure.country,
countryArr: firstRelation.arrival.country,
}),
params: true,
replace: true,
});
}, 500)
}
}, [data?.relations, firstSelected, navigate, searchId]);
data here related to a useQuery. After removing the loader from the page it worked for the inital load. That means when the useEffect was executed after querying necessary data. It wouldn't work with cached data after returning to the dashboard. The current dirty workaround is a setTimeout. I'm currently trying to reproduce the issue in this repo: https://github.com/lukaskoeller/tanstack-react-router-useEffect-navigate-reproduction. Yet I couldn't reproduce it but will let you know once I could Overall the behavior in our app is really weird. Now I experienced search params for /benchmark are applied for other pages like /calculator. Also removing certain components and adding them suddently made the navigation as in the code above work.
frozen-sapphire
frozen-sapphire•14mo ago
Shouldn't you be cleaning up the setTimeout here? If not, across renders an outdated setTimeout could fire that'd cause old navigations to be fired.
eastern-cyan
eastern-cyanOP•14mo ago
yeah you're right. That should be fixed. Nonetheless, the last hours I'm trying to see what is causing the buggy behavior with search params in our app, I removed the setTimeout @Manuel Schiller @Sean Cassiere Ok, at least one thing I was able to reproduce now. See reproducer. https://github.com/lukaskoeller/tanstack-react-router-useEffect-navigate-reproduction The issue appears when two useEffect are executed shortly after each other. The time the second useEffect executes the navigate (see example below), the old params are still empty ({}) although the navigate of the useEffect was executed first and applied firstId. Thus, expected would be that the old of the navigate running shortly after is not empty ({}) but holds the firstId ({ firstId: 1337 }).
useEffect(() => {
void navigate({
search: (old) => {
return {
...old,
secondId: 42,
};
},
});
}, [navigate]);
useEffect(() => {
void navigate({
search: (old) => {
return {
...old,
secondId: 42,
};
},
});
}, [navigate]);
Now that I'm thinking about it, it is probably because the Promise of the first navigate hasn't resolved at the time the second navigate fires 🤔
exotic-emerald
exotic-emerald•14mo ago
yes, most likely. why do you have two useEffect that both navigate independently from each other ?
eastern-cyan
eastern-cyanOP•14mo ago
The other useEffect lives in another component and is executed as soon as certain params are available which triggers isLoading of another useQuery There's another issue with default search params. See reproducer: https://github.com/lukaskoeller/tanstack-react-router-useEffect-navigate-reproduction?tab=readme-ov-file#reproduction-2 Given the following validateSearch:
validateSearch: object({
param1: number().optional().default(7),
param2: string().optional().default("defaultValue1"),
}),
validateSearch: object({
param1: number().optional().default(7),
param2: string().optional().default("defaultValue1"),
}),
when you navigate the page, useSearch returns the default values, but they are not attached to the URL. That only happens when you reload the page. I would expect search params in the URL anytime when params are returned via useSearch Turns out there's already an open github issue for that: https://github.com/TanStack/router/issues/1184 Created a github issue for this one: https://github.com/TanStack/router/issues/2028

Did you find this page helpful?