Skip to content

Commit 41860a7

Browse files
committed
searchparams race condition
1 parent 2120afe commit 41860a7

File tree

2 files changed

+69
-45
lines changed

2 files changed

+69
-45
lines changed

src/components/OptimadeClient/DropdownSelectors/childProviderDropdown.jsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,15 @@ export default function ChildProviderDropdown({
99
selectedProvider,
1010
selectedChild,
1111
onSelectChild,
12+
childEntries,
13+
loadingChildren,
1214
}) {
1315
const [customInput, setCustomInput] = useState(
1416
selectedChild?.id === "__custom__" ? selectedChild.base_url : "",
1517
);
1618

1719
const lastSubmittedCustom = useRef(customInput);
1820

19-
const { data, isLoading: loadingChildren } = useQuery({
20-
queryKey: ["provider-links", selectedProvider?.attributes?.base_url],
21-
queryFn: () => getProviderLinks(selectedProvider.attributes.base_url),
22-
enabled: !!selectedProvider?.attributes?.base_url,
23-
staleTime: Infinity,
24-
});
25-
26-
const childEntries =
27-
data?.children?.map((c) => ({
28-
id: c.id,
29-
...(c.attributes ?? {}),
30-
})) ?? [];
31-
3221
useEffect(() => {
3322
if (!selectedProvider || selectedProvider.id === "__custom__") return;
3423
if (loadingChildren) return;

src/components/OptimadeClient/index.jsx

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect, useCallback } from "react";
2-
import { getProvidersList, getStructures } from "../../api";
2+
import { getProvidersList, getProviderLinks, getStructures } from "../../api";
33
import OptimadeHeader from "./OptimadeHeader";
44
import OptimadeFilters from "./OptimadeFilters";
55
import OptimadeFAQs from "./OptimadeFAQs";
@@ -53,51 +53,84 @@ export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) {
5353

5454
const providers = providersData?.data ?? [];
5555

56-
// --- URL → state (registry mode only) ---
56+
// --- Children from providers list ---
57+
const { data: childData, isLoading: loadingChildren } = useQuery({
58+
queryKey: ["provider-links", selectedProvider?.attributes?.base_url],
59+
queryFn: () => getProviderLinks(selectedProvider.attributes.base_url),
60+
enabled: !!selectedProvider?.attributes?.base_url,
61+
staleTime: Infinity,
62+
});
63+
64+
const childEntries =
65+
childData?.children?.map((c) => ({
66+
id: c.id,
67+
...(c.attributes ?? {}),
68+
})) ?? [];
69+
70+
// --- 1. URL → Provider State ---
5771
useEffect(() => {
58-
if (isCustom) return;
59-
if (!providers.length || !providerParam) return;
72+
if (isCustom || !providers.length || !providerParam) return;
6073

6174
const provider = providers.find((p) => p.id === providerParam);
62-
if (provider) setSelectedProvider(provider);
75+
if (provider && selectedProvider?.id !== provider.id) {
76+
setSelectedProvider(provider);
77+
}
6378
}, [providers, providerParam, isCustom]);
6479

80+
// --- 2. URL → Child State ---
6581
useEffect(() => {
66-
if (isCustom) return;
67-
if (!selectedProvider || !dbParam) return;
82+
if (isCustom || !dbParam || !childEntries.length) return;
6883

69-
const child = selectedProvider.children?.find((c) => c.id === dbParam);
70-
if (child) setSelectedChild(child);
71-
}, [selectedProvider, dbParam, isCustom]);
84+
if (selectedChild?.id !== dbParam) {
85+
const child = childEntries.find((c) => c.id === dbParam);
86+
if (child) {
87+
setSelectedChild(child);
88+
}
89+
}
90+
}, [childEntries, dbParam, isCustom]);
7291

7392
// --- state → URL ---
7493
useEffect(() => {
75-
// --- CUSTOM MODE ---
76-
if (selectedChild?.id === "__custom__" && selectedChild.base_url) {
77-
setSearchParams({ base_url: selectedChild.base_url }, { replace: true });
78-
return;
79-
}
94+
// 1. Determine if we are in Custom Mode
95+
const isCurrentlyCustom = selectedChild?.id === "__custom__";
8096

81-
// --- REGISTRY MODE ---
82-
if (selectedProvider?.id && selectedChild?.id) {
83-
setSearchParams(
84-
{
85-
provider: selectedProvider.id,
86-
db: selectedChild.id,
87-
},
88-
{ replace: true },
89-
);
90-
return;
91-
}
97+
const params = new URLSearchParams();
9298

93-
// --- PARTIAL / RESET ---
94-
if (selectedProvider?.id) {
95-
setSearchParams({ provider: selectedProvider.id }, { replace: true });
96-
return;
99+
if (isCurrentlyCustom) {
100+
// Only set base_url, ignore provider/db
101+
if (selectedChild?.base_url) {
102+
params.set("base_url", selectedChild.base_url);
103+
} else if (customUrl) {
104+
// Keep existing URL param if state hasn't updated yet
105+
params.set("base_url", customUrl);
106+
}
107+
} else {
108+
// --- REGISTRY MODE ---
109+
if (selectedProvider?.id) {
110+
params.set("provider", selectedProvider.id);
111+
}
112+
113+
if (selectedChild?.id && selectedChild.id !== "__custom__") {
114+
params.set("db", selectedChild.id);
115+
} else if (dbParam && !selectedChild && selectedProvider) {
116+
// PERSIST the db param from URL while the provider's children are loading
117+
params.set("db", dbParam);
118+
}
97119
}
98120

99-
setSearchParams({}, { replace: true });
100-
}, [selectedProvider, selectedChild]);
121+
// prevent loops by comparing old to new
122+
const newString = params.toString();
123+
if (newString !== searchParams.toString() && newString !== "") {
124+
setSearchParams(params, { replace: true });
125+
}
126+
}, [
127+
selectedProvider,
128+
selectedChild,
129+
isCustom,
130+
customUrl,
131+
dbParam,
132+
setSearchParams,
133+
]);
101134

102135
// --- Structures / results via TanStack Query ---
103136
const { data: resultsData, isLoading: isLoading } = useQuery({
@@ -159,6 +192,8 @@ export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) {
159192
selectedProvider={selectedProvider}
160193
selectedChild={selectedChild}
161194
onSelectChild={setSelectedChild}
195+
childEntries={childEntries}
196+
loadingChildren={loadingChildren}
162197
/>
163198
</div>
164199

0 commit comments

Comments
 (0)