Home > Back-end >  React Router Dom and object in in search parameters
React Router Dom and object in in search parameters

Time:01-25

I am using React Router Dom v6. I would like to store some object search parameters in the URL. Right now, I am basically doing something like this :

  const [searchParams, setSearchParams] = useSearchParams();
  const allSearchParams = useMemo(() => {
    const params: Record<string, string> = {};
    for (const [key, value] of searchParams.entries()) {
      if (value.startsWith('{') || value.startsWith('[')) {
        try {
          params[key] = JSON.parse(value);
        } catch {
          params[key] = value;
        }
      } else {
        params[key] = value;
      }
    }
    return params;
  }, [searchParams]);

And when writing in the URL, I do:

      const newF: Record<string, string> = { ...nextFilter };
      Object.keys(newF).forEach((key) => {
        if (typeof newF[key] === 'object' && newF[key]) {
          newF[key] = JSON.stringify(newF[key]);
        }
      });
      setSearchParams(createSearchParams(newF), {
        replace: replaceSearch,
      });

But this feels pretty hacky. Is there a proper way to store objects in the URL properly and safely? For example:

const filters = {
 name: "user1",
 region: {
   city: "Sydney",
   country: "Australia"
 }
}

CodePudding user response:

You can simplify your encoding and decoding process. You can use the below functions; you can add them in their own file and import them:

import {createSearchParams} from "react-router-dom"

export const encodeSearchParams = (params) => createSearchParams(params);
export const decodeSearchParams = (searchParams) => {
  return [...searchParams.entries()].reduce((acc, [key, val]) => {
    try {
      return {
        ...acc,
        [key]: JSON.parse(val)
      };
    } catch {
      return {
        ...acc,
        [key]: val
      };
    }
  }, {});
};

This way, you don't have to memoize them. And you can use them like below, for example:

function HomePage() {
  const [searchParams, setSearchParams] = useSearchParams();

  function handleQueryParamsChange() {
    const filters = {
      name: "user1",
      region: {
        city: "Sydney",
        country: "Australia"
      }
    };

    const params = {
      filters: JSON.stringify(filters),
      anotherField: "Simple String"
    };

    setSearchParams(encodeSearchParams(params));
  }

  console.log(decodeSearchParams(searchParams).filters);
  console.log(decodeSearchParams(searchParams).anotherField);

  return (
    <div>
      <button onClick={handleQueryParamsChange} className="page">
        Update query params
      </button>
    </div>
  );
}

  • Related