Beginner's Guide To useSearchParams In Remix (With Code Examples)

Zach Taylor
Zach Taylor
hero image

Ever wonder how apps seem to remember filters, searches, or specific pages even after refreshing or sharing the link?

Well, that's the magic of search parameters, and with Remix’s useSearchParams, you can add that same kind of smooth, user-friendly experience to your own apps.

If you're not familiar with search parameters, don't worry - they're just a way to store and share information right in the URL. And once you get the hang of useSearchParams, you'll see how it makes things like filtering, searching, and even pagination a breeze.

In this guide, I'm going to break down what search parameters are, why they matter, and how to use useSearchParams in your Remix projects. We'll also dive into some easy-to-follow examples to help you see it in action.

Ready to make your Remix apps even more powerful? Let’s get into it!

Sidenote: If you enjoy this guide and want to take an even deeper dive in Remix, then check out my complete Remix course:

learn remix this year

If you're a Developer who is serious about taking your coding skills and career to the next level by building better websites, then this is the course for you.

This course covers everything from beginner to advanced topics and building your own full-stack project!

With that out of the way, let’s get into the guide…

What is `useSearchParams`?

useSearchParams is a hook provided by Remix that lets you work with search (or query) parameters in a URL. If you've used React Router before, this will feel familiar because it's built on top of that package.

If you’ve never used that then let’s break it down.

In simple terms, search parameters are the little bits of info in a URL that appear after the question mark (?).

They store and share things like filters or search terms right in the URL, making your app more user-friendly, as they allow the app to remember a user's choices, even if they refresh or share the link.

For example

Imagine a user is shopping for pillows on a website, and they want to filter the results to only see large, blue pillows. After applying the filters, the URL might look like this:

https://example.com/pillows?color=blue&size=large

In this case, color=blue and size=large are the search parameters. These parameters work as key-value pairscolor is the key and blue is the value, while size is another key with large as its value. Multiple parameters are separated by an ampersand (&), as seen here.

Now, here’s where useSearchParams comes into play.

Remix lets you access and manipulate these parameters directly within your components using useSearchParams. This hook gives you an array with two items:

  • An instance of URLSearchParams, which allows you to read the current search parameters
  • A setter function, which allows you to update them

Now that we understand the theory, let’s see how it’s done in practice.

Here’s how this works in a practical example:

import { useSearchParams } from '@remix-run/react';

function PillowFilter() {
  let [searchParams, setSearchParams] = useSearchParams();
  let color = searchParams.get('color') || 'none'; // Default to 'none' if not set

  const handleFilterChange = () => {
	setSearchParams((prev) => {
  	prev.set('color', 'green');
  	return prev;
	});
  };

  return (
	<div>
  	<p>Current Color Filter: {color}</p>
  	<button onClick={handleFilterChange}>Filter to Green</button>
	</div>
  );
}

In this example:

  • We use searchParams.get('color') to read the current color parameter from the URL. This allows the app to dynamically update and sync the user’s filters directly in the URL, ensuring that any user-selected settings—like filters—remain intact, even if the page is refreshed or shared
  • If no color parameter is found, it defaults to 'none'
  • When the user clicks the button, setSearchParams is used to update the color parameter in the URL to 'green'. This ties the app's state (the color filter) directly to the URL, making it easy to maintain and share

But why is this feature so valuable in a Remix app? That’s where the real benefits of using useSearchParams come into play…

Why use `useSearchParams`?

Let’s break down some of the main advantages that can significantly enhance your app’s user experience and performance.

State Management: React vs. Remix

In React, we often use hooks like useState or useReducer to manage state, but these are limited to the client side. This means that the server doesn't know anything about the state being held, which can cause issues when trying to sync between the two.

For example

If you're building a React app that uses useState to manage filters, and the user refreshes the page, they'll lose their filter settings because the state isn't preserved. Similarly, if they share the URL with someone else, the other person won't see the same filters applied.

Search parameters solve this problem because they live right in the URL. This means that both the server and the client can see them. So when Remix server-renders your application, it knows the exact state of the page because it can read the search parameters from the URL.

This has several benefits:

  1. Server and Client Sync: The server can render the page with the correct state without any additional data fetching or state management hacks
  2. State Persistence: The state persists across page refreshes since it's part of the URL
  3. Shareable URLs: Users can share the URL with others, and they'll see the same state (filters, search terms, etc.)

Leveraging Web Standards

One of the best things about using search parameters is that they take advantage of built-in web behavior.

For example

When you submit a form with the GET method, the default behavior is to send a request and append the form data as search parameters in the URL. This allows you to implement features like searching, filtering, or pagination with simple web forms, aligning your app with web standards.

Remix embraces this approach, allowing you to build apps that are both powerful and easy to maintain—no need to reinvent the wheel!

Declarative Code

useSearchParams fits perfectly with the declarative style of React. Instead of writing imperative code that directly manipulates the URL, you describe what the state of your parameters should be and let useSearchParams handle it.

For example

Let's say you're building a product filter for an e-commerce site.

With useSearchParams, you don't have to write complex code to manage the URL changes yourself. Instead, you define the filters and simply update the search parameters, and Remix will update the URL for you.

Why is this beneficial?

  • Cleaner Code: Keeps your code cleaner and easier to maintain.
  • Better Understanding: Easier for future developers (or even yourself) to understand how the filtering logic works.
  • Reliability: Ensures the URL and UI stay in sync, reducing potential bugs.

Seamless Integration with Remix

When you update the search parameters using setSearchParams, Remix triggers a navigation that re-fetches data from your loaders and re-renders the UI. This means you don't need to manually handle data fetching or worry about syncing the URL with the app state.

For example

Imagine you're working with paginated data, such as browsing through pages of products.

When the user changes the page (e.g., by clicking "Next"), you update the page search parameter using setSearchParams. Remix will then automatically trigger a fetch to get the next page of data and render it for the user.

const handleNextPage = () => {
  setSearchParams((prev) => {
	prev.set('page', nextPage);
	return prev;
  });
};

Why is this beneficial?

  • Efficiency: Reduces the amount of code you need to write
  • User Experience: Provides a smoother user experience since everything stays in sync without extra effort on your part
  • Fewer Bugs: Automatic re-fetching means fewer bugs related to data synchronization

How to use `useSearchParams`

Now that we understand what useSearchParams is and why it matters, let's dive into how to use it in your Remix application.

Step #1. Reading Search Parameters

Firstly, you need to import useSearchParams from Remix:

import { useSearchParams } from '@remix-run/react';

Then inside your component, you can use the useSearchParams hook. It returns an array where the first element is searchParams - which is an instance of URLSearchParams.

With searchParams, you can use its methods, like .get(), to read the value of a particular search parameter:

function SearchComponent() {
  let [searchParams] = useSearchParams();
  let query = searchParams.get('q') || '';

  return (
	<div>
  	<p>Search Query: {query}</p>
	</div>
  );
}

In this example, we're getting the value of the q parameter from the URL.

Step #2. Updating Search Parameters

To update search parameters, you can then use the second element that useSearchParams returns - the setter function (setSearchParams):

function SearchComponent() {
  let [searchParams, setSearchParams] = useSearchParams();
  let query = searchParams.get('q') || '';

  function updateQuery(newQuery) {
	setSearchParams((prev) => {
  	prev.set('q', newQuery);
  	return prev;
	});
  }

  return (
	<div>
  	<input
    	type="text"
    	value={query}
    	onChange={(e) => updateQuery(e.target.value)}
  	/>
	</div>
  );
}

In this example, we're updating the q parameter in the URL whenever the input value changes.

Further examples

Let's now take a look at some practical examples and use-cases of useSearchParams.

How to implement Search Functionality with `useSearchParams`

One of the most common use-cases for query parameters is implementing search functionality in your web application.

Users can type a search term, which gets added to the URL as a query parameter. Then, your app reads this search parameter and fetches the relevant data.

Here's a simple example of a search component using useSearchParams:

import { useSearchParams } from '@remix-run/react';

function Search() {
  let [searchParams] = useSearchParams();
  let query = searchParams.get('q') || '';

  return (
	<form method="GET">
  	<input name="q" defaultValue={query} />
  	<button type="submit">Search</button>
	</form>
  );
}

This component consists of a search box where a user can type their search term.

Notice that we’re not using the setSearchParams function in this example, because you don’t need it!

Instead, when the user submits the form, the browser updates the query parameter q in the URL with the entered search term because our input is named “q”. This is the default behavior of forms on the web!

Sidenote: I would avoid using setSearchParams whenever possible, since it requires you to write and maintain less code. Why write code to do something that forms already know how to do? Let the form take care of updating the search params in this case.

Pagination with `useSearchParams`

Let’s do an example where we use setSearchParams instead of using a form.

Query parameters are also used frequently for navigating through paginated resources. You can represent the current page as a query parameter, and useSearchParams can help set or update this parameter as the user navigates through the pages.

Here's a pagination component example:

import { useSearchParams } from '@remix-run/react';

function Pagination({ total }) {
  let [searchParams, setSearchParams] = useSearchParams();
  let page = parseInt(searchParams.get('page')) || 1;

  function onPageChange(newPage) {
	setSearchParams((prev) => {
  	prev.set('page', newPage);
  	return prev;
	});
  }

  return (
	<div>
  	{page > 1 && (
    	<button onClick={() => onPageChange(page - 1)}>Previous</button>
  	)}
  	{page < total && (
    	<button onClick={() => onPageChange(page + 1)}>Next</button>
  	)}
	</div>
  );
}

In this component, we're reading the page parameter from the URL and providing buttons to navigate to the previous or next page. When a button is clicked, it updates the page parameter in the URL.

Now, we could write this example without setSearchParams if we wanted to (like I advised in the previous example). To do that, we’d have to wrap each button in a form and give both buttons the name “page” and set their values to “page - 1” and “page + 1”, like this:

import { useSearchParams } from "@remix-run/react";

function Pagination({ total }) {
  let [searchParams] = useSearchParams();
  let page = parseInt(searchParams.get("page")) || 1;

  return (
	<div>
  	{/* ...render items on current page */}
  	{page > 1 && <Form><button name=”page” value={page - 1}>Previous</button></Form>}
  	{page < total && <Form><button name=”page” value={page + 1}>Next</button></Form>}
	</div>
  );
}

This code is actually a bit simpler than the setSearchParams version, which is why I recommend using forms to update the search parameters whenever possible.

Personally, I think it more clearly communicates the intention of the code, which is always my first priority, as we want it to be as clear as possible to our future selves and other developers what the code is doing.

It's time to test useSearchParams in your own projects

So as you can see, useSearchParams makes managing search parameters in Remix effortless, letting you sync state between the client and server, maintain shareable URLs, and embrace web standards.

With its declarative style, you’ll write cleaner, more maintainable code while ensuring a smooth user experience.

Ready to take your Remix projects to the next level? Start using useSearchParams to manage your app’s state directly in the URL. Try it out in your own project today and see how much easier and more powerful your development process becomes!

P.S.

Remember, if you want to take an even deeper dive in Remix, then check out my complete Remix course:

learn remix this year

This course covers everything from beginner to advanced topics and building your own full-stack project!

Plus, once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students, and working Web Developers.


More from Zero To Mastery

Remix vs Next.js - Which is best? preview
Popular
Remix vs Next.js - Which is best?

Learn each framework's key features, pros, and cons in this in-depth comparison guide so that you can choose the best option for your project needs and goals.

Which Tech Career Is Right For Me? (3-Step Guide To Help You Decide!) preview
Which Tech Career Is Right For Me? (3-Step Guide To Help You Decide!)

Want to start a career in tech but not sure of the options or which you'll be good at? This in-depth guide will help you figure that out and give you the resources to get started in each of the top tech careers!

How To Become A Web Developer (From Complete Beginner to Hired) preview
How To Become A Web Developer (From Complete Beginner to Hired)

Want to become a Web Developer but not sure how? Our step-by-step guide shows you how to go from beginner to hired (without wasting $1,000s on a bootcamp or degree). And we answer all your FAQ.