Skip to content

Commit 4f295bd

Browse files
committed
Fix bug with search params removal
1 parent 4640b2a commit 4f295bd

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

packages/react-router-dom/__tests__/search-params-test.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,40 @@ describe("useSearchParams", () => {
125125
);
126126
expect(node.innerHTML).toMatch(/The new query is "Ryan Florence"/);
127127
});
128+
129+
it("allows removal of search params when a default is provided", () => {
130+
function SearchPage() {
131+
let [searchParams, setSearchParams] = useSearchParams({
132+
value: "initial",
133+
});
134+
135+
return (
136+
<div>
137+
<p>The current value is "{searchParams.get("value")}".</p>
138+
<button onClick={() => setSearchParams({})}>Click</button>
139+
</div>
140+
);
141+
}
142+
143+
act(() => {
144+
ReactDOM.createRoot(node).render(
145+
<MemoryRouter initialEntries={["/search?value=initial"]}>
146+
<Routes>
147+
<Route path="search" element={<SearchPage />} />
148+
</Routes>
149+
</MemoryRouter>
150+
);
151+
});
152+
153+
let button = node.querySelector<HTMLInputElement>("button")!;
154+
expect(button).toBeDefined();
155+
156+
expect(node.innerHTML).toMatch(/The current value is "initial"/);
157+
158+
act(() => {
159+
button.dispatchEvent(new Event("click", { bubbles: true }));
160+
});
161+
162+
expect(node.innerHTML).toMatch(/The current value is ""/);
163+
});
128164
});

packages/react-router-dom/dom.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,17 @@ export function createSearchParams(
8888

8989
export function getSearchParamsForLocation(
9090
locationSearch: string,
91-
defaultSearchParams: URLSearchParams
91+
defaultSearchParams: URLSearchParams | null
9292
) {
9393
let searchParams = createSearchParams(locationSearch);
9494

95-
for (let key of defaultSearchParams.keys()) {
96-
if (!searchParams.has(key)) {
97-
defaultSearchParams.getAll(key).forEach((value) => {
98-
searchParams.append(key, value);
99-
});
95+
if (defaultSearchParams) {
96+
for (let key of defaultSearchParams.keys()) {
97+
if (!searchParams.has(key)) {
98+
defaultSearchParams.getAll(key).forEach((value) => {
99+
searchParams.append(key, value);
100+
});
101+
}
100102
}
101103
}
102104

packages/react-router-dom/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,13 +853,17 @@ export function useSearchParams(
853853
);
854854

855855
let defaultSearchParamsRef = React.useRef(createSearchParams(defaultInit));
856+
let hasSetSearchParamsRef = React.useRef(false);
856857

857858
let location = useLocation();
858859
let searchParams = React.useMemo(
859860
() =>
861+
// Only merge in the defaults if we haven't yet called setSearchParams.
862+
// Once we call that we want those to take precedence, otherwise you can't
863+
// remove a param with setSearchParams({}) if it has an initial value
860864
getSearchParamsForLocation(
861865
location.search,
862-
defaultSearchParamsRef.current
866+
hasSetSearchParamsRef.current ? null : defaultSearchParamsRef.current
863867
),
864868
[location.search]
865869
);
@@ -870,6 +874,7 @@ export function useSearchParams(
870874
const newSearchParams = createSearchParams(
871875
typeof nextInit === "function" ? nextInit(searchParams) : nextInit
872876
);
877+
hasSetSearchParamsRef.current = true;
873878
navigate("?" + newSearchParams, navigateOptions);
874879
},
875880
[navigate, searchParams]

0 commit comments

Comments
 (0)