.claude/skills/react-router-setsearchparams-gotcha/SKILL.md
Fix React Router setSearchParams overwriting existing query parameters. Use when: (1) URL query params disappear after navigation, (2) deep links with ?card=X or similar params stop working after board/page switch, (3) setSearchParams({ key: value }) is erasing other params. Covers the functional update pattern to preserve existing params.
npx skillsauth add Dbochman/dotfiles react-router-setsearchparams-gotchaInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When using React Router's useSearchParams hook, the common pattern of calling
setSearchParams({ key: value }) with an object completely replaces all query
parameters instead of merging. This breaks deep links and loses user context.
?board=roadmap&card=my-card lose the card param when switching boardssetSearchParams({ board: newBoardId }) or similar object syntaxUse the functional update pattern instead of the object pattern:
// BAD - Overwrites all params
setSearchParams({ board: newBoardId });
// GOOD - Preserves existing params
setSearchParams((prev) => {
const next = new URLSearchParams(prev);
next.set('board', newBoardId);
return next;
});
If some params should be removed (e.g., card IDs are board-specific):
setSearchParams((prev) => {
const next = new URLSearchParams(prev);
next.set('board', newBoardId);
next.delete('card'); // Card IDs are board-specific
return next;
});
For frequent use, create a helper:
function updateSearchParams(
setSearchParams: SetURLSearchParams,
updates: Record<string, string | null>
) {
setSearchParams((prev) => {
const next = new URLSearchParams(prev);
for (const [key, value] of Object.entries(updates)) {
if (value === null) {
next.delete(key);
} else {
next.set(key, value);
}
}
return next;
});
}
// Usage
updateSearchParams(setSearchParams, { board: newBoardId, card: null });
?board=roadmap&card=my-card&view=gridBefore (broken):
// BoardSelector.tsx
function handleBoardSelect(boardId: string) {
setSearchParams({ board: boardId }); // Loses ?card=X, ?view=Y, etc.
setIsOpen(false);
}
After (fixed):
// BoardSelector.tsx
function handleBoardSelect(boardId: string) {
setSearchParams((prev) => {
const next = new URLSearchParams(prev);
next.set('board', boardId);
next.delete('card'); // Intentionally clear board-specific params
return next;
});
setIsOpen(false);
}
setSearchParams({ key: value }) is convenient but dangerousURLSearchParams and must return URLSearchParamsdevelopment
Search the web for current information, news, facts, and answers. Use when asked questions about current events, needing to look something up, finding websites, researching topics, or when you need up-to-date information beyond your training data.
development
Summarize any URL, YouTube video, podcast, PDF, or file into concise text. Use when asked to read an article, summarize a link, get the gist of a video or podcast, extract content from a URL, or when you need to understand what a web page or document contains.
development
Play music via Spotify and control Google Home speakers. Use when asked to play music, songs, artists, playlists, podcasts, or control speakers/volume/audio.
testing
Create new OpenClaw skills, modify and improve existing skills, and measure skill performance with evals. Use when users want to create a skill from scratch, update or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy. Also use when asked to "make a skill", "turn this into a skill", "improve this skill", or "test this skill".