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