react-router v6: Navigate to a URL with searchParams
Asked Answered
W

7

50

I'm using react-router v6. I want to navigate to a URL that has searchParams, but I'm not seeing a way to do this out of the box. useNavigate allows me to navigate to a URL by passing in a string. useSearchParams allows me to set searchParams on the current page.

I could generate the searchParams using createSearchParams and then convert it to a string and append it to the end of the URL with a ? in between, but that seems like a hack.

I'd like to be able to do something like:

const navigate = useNavigate();

// listing?foo=bar
navigate("listing", {
    params: {
        foo: "bar"
    }
});

My hacky workaround:

function useNavigateParams() {
    const navigate = useNavigate();

    return (url: string, params: Record<string, string | string[]>) => {
        const searchParams = createSearchParams(params).toString();
        navigate(url + "?" + searchParams);
    };
}

const navigateParams = useNavigateParams();

navigateParams("listing", {
    foo: "bar"
});

Did I miss something from the documentation?

Wabash answered 19/1, 2021 at 22:48 Comment(3)
to make things less confusing for this conversation, in react-router speak "params" are the variables in the URI aka /:id is params.id, what you're talking about is commonly refered to as the location.search part aka query-string. there's a nice helper library that's fairly common for these ops, but I don't think that react-router ships with this stringing / parsing utilites npmjs.com/package/query-stringBurgenland
As the question appears to be about react-router-v6, you might want to update the tag (v4)Disney
you can use 'useRouter' from (usehooks.com)Sinewy
W
70

Update

It's no longer necessary to prepend ? to search (as of ~September 2021):

import { createSearchParams, useNavigate } from "react-router-dom";

...

const navigate = useNavigate();

navigate({
    pathname: "listing",
    search: createSearchParams({
        foo: "bar"
    }).toString()
});

This isn't quite as simplified as I'd like, but I think it's the closest we can get currently. navigate does support passing in a search query string (not an object).

import { createSearchParams, useNavigate } from "react-router-dom";

...

const navigate = useNavigate();

navigate({
    pathname: "listing",
    search: `?${createSearchParams({
        foo: "bar"
    })}`
});

Source: https://github.com/ReactTraining/react-router/issues/7743#issuecomment-770296462

Wabash answered 18/2, 2021 at 18:7 Comment(2)
The above quoted method works for the first time .i.e, from Parent1 > child1 When I use the same logic, by using Parent2, Child2, its getting navigated to "Child1" instead of "Child2" The route set for parent1 and child 1 is <Route path="/parent1" element={<Parent1 />} /> <Route path="/parent1/child1" element={<child1 />} /> <Route path="/parent2" element={<Parent2 />} /> <Route path="/parent2/child2" element={<child2 />} /> The params for Child 1 and Child2 are set as quoted in github navigate ({pathname: "listing",search: '?' + createSearchParams({ foo: "bar" })})Homozygous
Hello, I tried using your approach but whenever it redirects, the query parameters are removed. Do you have any idea why? Thank you!Lauderdale
D
15

What you have is looks fine to me. Using the generatePath and createSearchParams utilities it may be a little cleaner, but it is still the same basic idea.

import { generatePath, useNavigate } from "react-router-dom";

...

const useNavigateParams = () => {
  const navigate = useNavigate();

  return (url: string, params: Record<string, string | string[]>) => {
    const path = generatePath(":url?:queryString", {
      url,
      queryString: createSearchParams(params).toString()
    });
    navigate(path);
  };
};

If you think about it this isn't much of a hack, the URL needs to be defined somewhere, whether it's the path params or part of the query string, you still need to provide that detail and build a path string to navigate to.

Demo - POC

Edit react-router-v6-navigate-to-a-url-with-searchparams

RRDv6.4 update

import { createSearchParams, useNavigate } from "react-router-dom";

...

const useNavigateParams = () => {
  const navigate = useNavigate();

  return (pathname, params) => {
    const path = {
      pathname,
      search: createSearchParams(params).toString()
    };
    navigate(path);
  };
};

Edit react-router-v6-navigate-to-a-url-with-searchparams (forked)

Danner answered 20/1, 2021 at 0:18 Comment(2)
Hello, I tried using your approach but whenever it redirects, the query parameters are removed. Do you have any idea why? Thank you!Lauderdale
@Lauderdale Dunno, we would probably need to see your code to see what it's doing. If you like you can create a new post on stackoverflow with the relevant minimal reproducible example and details regarding the issue and any debugging steps you've taken. Feel free to ping me here in a comment with a link to your post and I can take a look when available.Danner
R
13

To do this elegantly, you should use the useSearchParams hook instead of useNavigate.

As specified in the doc:

The setSearchParams function works like navigate, but only for the search portion of the URL. Also note that the second arg to setSearchParams is the same type as the second arg to navigate.

import { useSearchParams } from "react-router-dom";

...

const [searchParams, setSearchParams] = useSearchParams()

...

const handleClick = () => {
    searchParams.set('foo', 'bar');
    setSearchParams(searchParams)
}
Rafael answered 14/3, 2022 at 10:46 Comment(3)
Using setSearchParams() at the same time as navigate() does not work, the route gets messed up.Holism
@Holism that's the problem I've faced too, one always overwrites the other so you either navigate to the new path or you get the search params on the current pathKismet
Why does this answer have so many upvotes? It's wrong, it won't work for navigation.Whilst
C
5

Tested with [email protected]

const navigate = useNavigate();
navigate({ pathname: '/otherpage/', search: "?param1=123" });

Or with createSearchParams from react-router-dom

import { createSearchParams } from "react-router-dom";
const navigate = useNavigate();
navigate({ 
  pathname: '/otherpage/', 
  search: createSearchParams({ params1: "123" }).toString() 
});
Cadence answered 11/7, 2023 at 20:20 Comment(0)
T
1

There is a chance you might want to preserve the search in the URL and only change some values. useSearchParams doesn't seem to work for this purpose, because the first value returned in the hook is an empty object, while it would make more sense for it populated with the search params which are already in the URL. Bad design imho. However, I found a way to achieve the expected behaviour and only change a portion of the parameters using the react router in combination with serialize-query-params

// this goes right below the component declaration,
// where all the hooks are called
const navigate = useNavigate();

....
// this goes inside the function to change the search
// here we merge the new param with the current ones
const newLocation = updateInLocation(
  { foo: 'bar' },
  location
);

navigate(newLocation);
Tweed answered 7/2, 2023 at 14:6 Comment(0)
G
0

That's how I solved it:

I used the native URLSearchParams because I needed the same key to have more than one value.

const navigate = useNavigate();
const navigateToMyNextPage = () => {
  const searchParams = new URLSearchParams();
  searchParams.append("course", '9877');
  searchParams.append("course", '111'); // same-key again
  searchParams.append("time-of-day", 'morning');

  navigate({
    pathname: "../students",
    search: searchParams.toString(),
  });
}

This will navigate to the students page in my app like this -->>

something/students?course=9877&course=111&time-of-day=morning
Glycine answered 16/7, 2024 at 13:15 Comment(0)
M
-1

you can use both of them in an easy way:

import { useNavigate, useSearchParams } from "react-router-dom";

...

const [searchBarParams, setSearchBarParams] = useSearchParams();
const navigate = useNavigate();

...


const handleChange = (event, value) => {
    navigate("/")
    searchBarParams.set("foo",value)
    setSearchBarParams(searchBarParams);
}
Motivation answered 9/12, 2022 at 20:48 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.