react-router v6: Navigate to a URL with searchParams

Viewed 32340

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?

3 Answers

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

What you have is looks fine to me. Using the generatePath utility 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

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)
}
Related