Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-router v6: warning You should call navigate() in a React.useEffect #211

Closed
d9k opened this issue Apr 4, 2022 · 9 comments · May be fixed by #266
Closed

react-router v6: warning You should call navigate() in a React.useEffect #211

d9k opened this issue Apr 4, 2022 · 9 comments · May be fixed by #266

Comments

@d9k
Copy link

d9k commented Apr 4, 2022

Used RouteAdapter example:
https://github.com/pbeshai/use-query-params/blob/master/examples/react-router-6/src/index.js
#196 (comment)

My component code:

const MyComponent = () => {
  const [filter, setFilter] = useQueryParam('filter', ObjectParam);

  useEffect(() => {
    if (!filter) { {
      setFilter({ city: 'London' });
    }
  }, [filter, setFilter]);

Getting an error:

You should call navigate() in a React.useEffect(), not when your component is first rendered

And redirect doesn't work.

Temporary solution

const MyComponent = () => {
  const [firstRenderDone, setFirstRenderDone] = useState(false);
  const [filter, setFilter] = useQueryParam('filter', ObjectParam);

  useEffect(() => {
    if (firstRenderDone && !filter) { {
      setFilter({ city: 'London' });
    }
  }, [filter, firstRenderDone, setFilter]);

  useEffect(() => {
    setFirstRenderDone(true);
  }, []);

How can I improve RouteAdapter to not implement firstRenderDone hack in every component I need redirect as soon as possible?

@Resetand
Copy link

Resetand commented May 9, 2022

Any updates? :)

@jmcpeak
Copy link
Contributor

jmcpeak commented Jun 16, 2022

Any updates? :)

I am using the RouteAdapter fix as provider here:
https://www.robinwieruch.de/react-router-search-params/

@Shaddix
Copy link
Contributor

Shaddix commented Jul 24, 2022

You could also check out the port of useQueryParams which uses react-router's API (i.e. useSearchParams) directly
https://github.com/mcctomsk/react-router-url-params#usequeryparams

@pbeshai
Copy link
Owner

pbeshai commented Jul 25, 2022

Hi there, support for React Router 6 has been added to v2.0.0-rc.0. Give it a shot and let me know if you still run into issues. See the changelog for migration info.

@pbeshai pbeshai closed this as completed Jul 25, 2022
@sKopheK
Copy link

sKopheK commented Dec 15, 2022

Any updates? :)

I am using the RouteAdapter fix as provider here: https://www.robinwieruch.de/react-router-search-params/

can you be more specific? i can't see anything about setting URL parameter right on the first render

i bumped into the same issue when wanting to change invalid URL params on the first render and this is my ugly HOTFIX w/ setTimeout:

const [pageNumber, setPageNumberUrlParam] = useQueryParam('page', withDefault(NumberParam, 0));

React.useEffect(() => {
    const validPageNumber = validatePageNumber(pageNumber);
    if (pageNumber !== validPageNumber) {
        setTimeout(() =>
            setPageNumberUrlParam(validPageNumber, 'replaceIn')
        );
    }
}, []);

@nichita-pasecinic
Copy link

Similar issue here

You should call navigate() in a React.useEffect(), not when your component is first rendered.

@Chrisdo82
Copy link

i get the same warning also with the ReactRouter6Adapter.

@lexanth
Copy link

lexanth commented Apr 26, 2023

@pbeshai this seems to still be an issue. This isn't just a warning in practice - react-router warns, then ignores the navigate call - https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/hooks.tsx#L181-L187

The issue comes from the order in which react executes effects (which was a surprise to me, but makes sense). Also not sure if this order is actually guaranteed...
https://codesandbox.io/s/priceless-pond-ck7gdn?file=/src/App.js

Effects in the child get executed before effects in the parent (but in order within a component). Because of how this library uses useNavigate in the provider (via the adapter), any effect in a child of the provider will execute before the effect in useNavigate, so the activeRef has not been set. Feels like this is basically from using useLocation in a way they haven't envisioned.

I'm not sure if there's a good way to handle this in use-query-params. A workaround for user code is to put the param setter in setTimeout. enableBatching: true also solves this because it does a similar thing, but marked as experimental so 🤷

@afn
Copy link

afn commented May 12, 2023

@pbeshai Can we reopen this issue?

We're having the same problem, and have solved/worked around it by using a modified ReactRouter6Adapter which wraps the navigate function so that any immediate calls to it are enqueued for future execution, and the queue is processed from a useEffect(). See PR: #266

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants