#Using navigate in useEffect leads to false routing

16 messages · Page 1 of 1 (latest)

candid kraken
#
  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?

candid kraken
#
    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?

wary lagoon
#

this most likely is a bug in router

#

can you please try it out ?

candid kraken
#

Yes this fixed it! Brillian. Thanks a lo @wary lagoon

candid kraken
# wary lagoon this most likely is a bug in router

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]);

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

candid kraken
#

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.

upper trellis
candid kraken
candid kraken
#

@wary lagoon @upper trellis

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]);
#

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 🤔

wary lagoon
candid kraken
candid kraken
#

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"),
}),

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

candid kraken