#Implementing a search pattern

1 messages · Page 1 of 1 (latest)

static flower
#

Hey all, I am implementing a search where on keystroke I need to call an api to get a list of results.

The search is in a header component, and the search results are in a non-nested body component, but both the search and results are both rendered on the same page. I'm wondering what the best Remix-y way of implementing this search would be

1.) On keystroke in the search, update the query params. Then in the results page, listen for the query params and re-run the results page loaders when the query params change
2.) On keystroke in the search, create a form action that returns a redirect to the results page with the query param like http://currentPage?q=search. Run this redirect on every keystroke

Appreciate any insight here!

sleek haven
#

Sounds like a combobox of some kind?

static flower
#

no, there's a search in the header, but the results show up in the body in a completely separate part of the page

#

they aren't nested, or in the same component

sleek haven
#

Ah, okay.

#

In 1, how are you thinking the url would look like here?

static flower
#

just like https://mySite.com/searchPage?query=[searchTextHere]

sleek haven
#

Got it.

#

Probably option 2, I would do it in the loader, and have the url query be my source of truth.

static flower
#

in option 1**** there would just be a useEffect listening for a query param change in the search results page, and then re-run its loaders

#

yeah that is pretty comparable

sleek haven
#

You don't actually need an effect at all if url is your source of truth.

static flower
#

yeah that makes sense

#

I'll give that a shot, thanks for the advice!

sleek haven
#

This is the entire client logic for my search bar here:

//todo this should probably be wrapped in a Form or useFetcher
export const SearchList = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const { collectionId } = useParams();

  const searchName = (e: React.ChangeEvent<any>) => {
    //reset pagination
    searchParams.delete("page");

    let allSearchParams = getSearchParams(searchParams);

    setSearchParams(
      {
        ...allSearchParams,
        name: e.target.value.toLowerCase(),
      },
      //disable scroll to top and prevent history
      { replace: true, state: { scroll: false } }
    );
  };

  return (
    <div
      className="bg-nested laptop:bg-primary border-color-primary flex h-12 w-full items-center 
    gap-4 border-t px-4 laptop:my-4 laptop:rounded-md laptop:border laptop:shadow-sm"
    >
      <FaSearch className="theme-color" />
      <input
        key={collectionId}
        placeholder={`Find...`}
        className="bg-nested laptop:bg-primary h-full w-full outline-none"
        name="name-search"
        onChange={debounce(searchName, 150)}
        defaultValue={searchParams.get("name") ?? ""}
      ></input>
    </div>
  );
};
static flower
#

wait I don't see this associated with a form action, so how are you getting the changes to re-fetch the new changes?

sleek haven
#

Then in your loader grab it with:

const url = new URL(request.url);
const search = url.searchParams.get("name-search");

static flower
#

oh you're doing it on submit?

sleek haven
#

Nope

#

setSearchParam is by definition a navigation.

static flower
#

oh interesting, wasn't aware of that

#

so setSearchParam will trigger the navigation event, and the loader action for the results will run and update the page

#

that makes sense

sleek haven
#

Yep! That's why url is your source of truth, or state, if you will.

static flower
#

perfect, I'll give that a shot. Really appreciate the help

sleek haven
#

No prob!

#

This pattern isn't well known yet, so give me a ping if you get stuck on something.

nimble dirge
wild lily
#

@sleek haven might be a bit late with this, but what implementation are you using for getSearchParams i have a need to get all the search params as a string and wondering if there's an efficient method for it

sleek haven
#

A couple ways:

  const location = useLocation();


  const getFilterOptions = (filter: string) => {
    const searchParams = new URLSearchParams(location.search);

    searchParams.set("filter", filter);

    return `?${searchParams.toString()}`;
  };

...

<Link to={getFilterOptions(filtervalue)}>

The URLSearchParams interface defines utility methods to work with the query string of a URL.