Skip to content

Commit 09d5da7

Browse files
committed
fix(home): resync form and results to URL on back/forward navigation
Round-2 review: the previous version only consumed search params on initial mount, so router.push from compare/swap/reset put history entries that the back button couldn't restore. Now a useEffect watches searchParams and resyncs username1/username2 + triggers a re-fetch when the URL pair differs from the last fetched pair. lastFetchedPairRef short-circuits the loop with our own router.push.
1 parent ee56062 commit 09d5da7

1 file changed

Lines changed: 72 additions & 2 deletions

File tree

app/page.tsx

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

3-
import { useMemo, useState } from "react";
3+
import { Suspense, useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
4+
import { useRouter, useSearchParams } from "next/navigation";
45
import { CompareForm } from "../components/compare-form";
56
import { ResultDashboard } from "../components/result-dashboard";
67
import { DashboardSkeleton } from "../components/skeletons";
@@ -16,14 +17,24 @@ type ApiResponse = {
1617
error?: string;
1718
};
1819

19-
export default function HomePage() {
20+
function HomePageInner() {
2021
const { t } = useTranslation();
22+
const router = useRouter();
23+
const searchParams = useSearchParams();
24+
const initialUsernames = searchParams.getAll("username");
25+
const initialUsername1 = initialUsernames[0] ?? "";
26+
const initialUsername2 = initialUsernames[1] ?? "";
2127
const [loading, setLoading] = useState(false);
2228
const [error, setError] = useState<string | null>(null);
29+
const [username1, setUsername1] = useState(initialUsername1);
30+
const [username2, setUsername2] = useState(initialUsername2);
2331
const [data, setData] = useState<{
2432
user1: UserResult;
2533
user2: UserResult;
2634
} | null>(null);
35+
// Track the URL pair we last fetched against so back/forward navigation
36+
// can resync the form and results without re-fetching identical pairs.
37+
const lastFetchedPairRef = useRef<[string, string] | null>(null);
2738

2839
const localizeErrorMessage = (message?: string) => {
2940
switch (message) {
@@ -43,6 +54,11 @@ export default function HomePage() {
4354
};
4455

4556
const handleCompare = async (u1: string, u2: string) => {
57+
lastFetchedPairRef.current = [u1, u2];
58+
router.push(
59+
`/?username=${encodeURIComponent(u1)}&username=${encodeURIComponent(u2)}`,
60+
{ scroll: false }
61+
);
4662
setLoading(true);
4763
setError(null);
4864
setData(null);
@@ -79,14 +95,56 @@ export default function HomePage() {
7995
}
8096
};
8197

98+
// Resync form + results to whatever the URL says — handles initial mount
99+
// AND back/forward navigation. We fetch only when the URL pair differs from
100+
// the last pair we fetched, so no infinite loop with the router.push above.
101+
const syncToUrl = useEffectEvent((u1: string, u2: string) => {
102+
setUsername1(u1);
103+
setUsername2(u2);
104+
105+
if (!u1 || !u2) {
106+
// Empty params: clear results so the empty state matches the URL.
107+
lastFetchedPairRef.current = null;
108+
setData(null);
109+
setError(null);
110+
return;
111+
}
112+
113+
const last = lastFetchedPairRef.current;
114+
if (last && last[0] === u1 && last[1] === u2) {
115+
// URL already reflects the most recent fetch; nothing to do.
116+
return;
117+
}
118+
119+
void handleCompare(u1, u2);
120+
});
121+
122+
useEffect(() => {
123+
const params = searchParams.getAll("username");
124+
syncToUrl(params[0] ?? "", params[1] ?? "");
125+
}, [searchParams]);
126+
82127
const skeleton = useMemo(() => <DashboardSkeleton />, []);
83128

84129
const reset = () => {
85130
setData(null);
86131
setError(null);
132+
setUsername1("");
133+
setUsername2("");
134+
router.push("/", { scroll: false });
87135
};
88136

89137
const swapUsers = () => {
138+
const nextUsername1 = username2;
139+
const nextUsername2 = username1;
140+
141+
setUsername1(nextUsername1);
142+
setUsername2(nextUsername2);
143+
router.push(
144+
`/?username=${encodeURIComponent(nextUsername1)}&username=${encodeURIComponent(nextUsername2)}`,
145+
{ scroll: false }
146+
);
147+
90148
if (!data) return;
91149
setData((d) => ({ user1: d!.user2, user2: d!.user1 }));
92150
};
@@ -97,6 +155,10 @@ export default function HomePage() {
97155

98156
<div className="w-full flex-1 max-w-6xl mx-auto px-4 py-10 space-y-6">
99157
<CompareForm
158+
username1={username1}
159+
username2={username2}
160+
setUsername1={setUsername1}
161+
setUsername2={setUsername2}
100162
onSubmit={handleCompare}
101163
loading={loading}
102164
reset={reset}
@@ -126,3 +188,11 @@ export default function HomePage() {
126188
</main>
127189
);
128190
}
191+
192+
export default function HomePage() {
193+
return (
194+
<Suspense fallback={<DashboardSkeleton />}>
195+
<HomePageInner />
196+
</Suspense>
197+
);
198+
}

0 commit comments

Comments
 (0)