(medium) trade-in/page.tsx useEstimateId: чтение window.location.search вместо useSearchParams → SSR hydration mismatch и нереактивность к смене URL #1425

Closed
opened 2026-06-15 05:54:40 +00:00 by bot-backend · 1 comment
Collaborator

Severity: medium · Категория: frontend · Файл: frontend/src/app/trade-in/page.tsx:17-22

page.tsx:17-22 — useEstimateId это обычная функция (не хук): при typeof window === 'undefined' возвращает null, на клиенте читает new URLSearchParams(window.location.search).get('id'). Импортированный next/navigation useSearchParams (page.tsx:4) не используется. Импакт: (1) Hydration mismatch — компонент 'use client', но всё равно пре-рендерится на сервере; при заходе по /trade-in?id=XXX сервер вернёт null → EmptyState, клиент при гидрации вернёт непустой id → загрузка/результат, дерево расходится (hydration warning + мигание контента). (2) Нереактивность — window.location.search читается только в момент рендера, без подписки на изменения URL; router.replace (page.tsx:48) и любая soft-навигация не триггерят перечитывание id. Как чинить: заменить useEstimateId на правильный хук — const id = useSearchParams().get('id') (App Router API уже импортирован), что и устранит оба дефекта.

Почему баг: 1) Hydration mismatch: при серверном рендере страницы по ссылке /trade-in?id=XXX функция вернёт null на сервере и непустой id на клиенте — React-дерево на сервере (EmptyState) и на клиенте (загрузка/результат) расходятся, что даёт hydration warning и мигание контента. 2) Нереактивность: функция читает window.location.search только в момент рендера и не подписана на изменения URL; soft-navigation через router.replace и любые последующие изменения query не триггерят перечитывание. Правильный Next.js App Router API (useSearchParams) импортирован, но проигнорирован — это и есть источник обоих дефектов.

Как чинить: Использовать импортированный useSearchParams(): const urlEstimateId = useSearchParams().get('id') — он реактивен и корректно отрабатывает на сервере/клиенте без ручного window-доступа. Удалить useEstimateId.


deep-audit «армия ботов 2» · verify+harden, confidence 0.85 · unit U84

**Severity:** medium · **Категория:** frontend · **Файл:** `frontend/src/app/trade-in/page.tsx:17-22` page.tsx:17-22 — useEstimateId это обычная функция (не хук): при typeof window === 'undefined' возвращает null, на клиенте читает new URLSearchParams(window.location.search).get('id'). Импортированный next/navigation useSearchParams (page.tsx:4) не используется. Импакт: (1) Hydration mismatch — компонент 'use client', но всё равно пре-рендерится на сервере; при заходе по /trade-in?id=XXX сервер вернёт null → EmptyState, клиент при гидрации вернёт непустой id → загрузка/результат, дерево расходится (hydration warning + мигание контента). (2) Нереактивность — window.location.search читается только в момент рендера, без подписки на изменения URL; router.replace (page.tsx:48) и любая soft-навигация не триггерят перечитывание id. Как чинить: заменить useEstimateId на правильный хук — const id = useSearchParams().get('id') (App Router API уже импортирован), что и устранит оба дефекта. **Почему баг:** 1) Hydration mismatch: при серверном рендере страницы по ссылке /trade-in?id=XXX функция вернёт null на сервере и непустой id на клиенте — React-дерево на сервере (EmptyState) и на клиенте (загрузка/результат) расходятся, что даёт hydration warning и мигание контента. 2) Нереактивность: функция читает window.location.search только в момент рендера и не подписана на изменения URL; soft-navigation через router.replace и любые последующие изменения query не триггерят перечитывание. Правильный Next.js App Router API (useSearchParams) импортирован, но проигнорирован — это и есть источник обоих дефектов. **Как чинить:** Использовать импортированный useSearchParams(): `const urlEstimateId = useSearchParams().get('id')` — он реактивен и корректно отрабатывает на сервере/клиенте без ручного window-доступа. Удалить useEstimateId. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.85 · unit U84</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:54:40 +00:00
bot-backend added the
scope/frontend
label 2026-06-15 11:02:02 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: frontend/src/app/trade-in/page.tsx:17-22 (функция useEstimateId), вызов на page.tsx:35. useSearchParams импортирован на page.tsx:4, но не используется.

Корень: useEstimateId() — обычная функция, не хук: typeof window === "undefined"null на сервере, на клиенте читает new URLSearchParams(window.location.search).get("id") (стр.19-21). Отсюда (1) hydration mismatch — компонент "use client", но пре-рендерится на сервере: при заходе по /trade-in?id=XXX сервер вернёт null → EmptyState, клиент при гидрации даст непустой id → загрузка/результат, дерево расходится; (2) нереактивность — window.location.search читается только в момент рендера, router.replace (page.tsx:48) и soft-навигация не триггерят перечитывание. useRouter уже импортирован, useSearchParams — нет в использовании.

Что править:

  • Заменить useEstimateId() на const urlEstimateId = useSearchParams().get("id") (App Router API уже импортирован) — реактивно и корректно SSR/CSR. Удалить функцию useEstimateId.
  • Примечание: useSearchParams в Next 15 требует <Suspense>-границы вокруг компонента — учесть при правке (обернуть страницу или вынести в дочерний клиентский компонент).

Что посмотреть:

  • Код: page.tsx:4,17-22,35, использование urlEstimateId в useEstimate (page.tsx:37-39); проверить наличие Suspense-boundary для prod-сборки.
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `frontend/src/app/trade-in/page.tsx:17-22` (функция `useEstimateId`), вызов на `page.tsx:35`. `useSearchParams` импортирован на `page.tsx:4`, но не используется. **Корень:** `useEstimateId()` — обычная функция, не хук: `typeof window === "undefined"` → `null` на сервере, на клиенте читает `new URLSearchParams(window.location.search).get("id")` (стр.19-21). Отсюда (1) hydration mismatch — компонент `"use client"`, но пре-рендерится на сервере: при заходе по `/trade-in?id=XXX` сервер вернёт `null` → EmptyState, клиент при гидрации даст непустой id → загрузка/результат, дерево расходится; (2) нереактивность — `window.location.search` читается только в момент рендера, `router.replace` (page.tsx:48) и soft-навигация не триггерят перечитывание. `useRouter` уже импортирован, `useSearchParams` — нет в использовании. **Что править:** - Заменить `useEstimateId()` на `const urlEstimateId = useSearchParams().get("id")` (App Router API уже импортирован) — реактивно и корректно SSR/CSR. Удалить функцию `useEstimateId`. - Примечание: `useSearchParams` в Next 15 требует `<Suspense>`-границы вокруг компонента — учесть при правке (обернуть страницу или вынести в дочерний клиентский компонент). **Что посмотреть:** - Код: `page.tsx:4,17-22,35`, использование `urlEstimateId` в `useEstimate` (page.tsx:37-39); проверить наличие Suspense-boundary для prod-сборки. - Vault: релевантных заметок не найдено.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1425
No description provided.