24 августа 2026 г. · 3 мин чтения
Кнопка нажимается и не делает ничего
На сайте перестала работать переписка. Симптом был один и очень неприятный: человек нажимает «Написать», и не происходит вообще ничего. Ни перехода, ни сообщения об ошибке, ни значка загрузки. Кнопка как будто не нажимается.
Такая поломка хуже честного «не получилось». Про ошибку с текстом понятно, что делать: перечитать, попробовать иначе, написать в поддержку. Про молчание непонятно ничего — человек решает, что сайт сломан, и уходит.
Причин оказалось три, и они накладывались друг на друга.
Первая. Серверное действие может не вернуть отказ, а бросить исключение. Чаще всего это происходит, когда истекла сессия: страж requireUser не отвечает «нельзя», он именно бросает. В обработчике нажатия без try/catch это исключение теряется, и функция просто не доходит до строки, которая что-то показывает.
Вторая. Действие отработало, а переход не случился. router.push, вызванный сразу после серверного действия, у нас молча не срабатывал: в базе разговор появлялся, а страница оставалась прежней. Разбираться в тонкостях того, почему именно, оказалось дороже, чем заменить переход на обычный window.location.assign — он делает ровно то, что обещает, ценой полной перезагрузки, которой в этом месте никто не заметит.
Третья, самая обидная. Страница, на которую вёл переход, падала с серверной ошибкой — о ней отдельная заметка. То есть даже если бы первые две работали, человек попал бы на 500.
Вывод, который стоит унести: в интерфейсе не должно быть состояния «ничего не произошло». Любое нажатие обязано закончиться одним из трёх — получилось, не получилось и вот почему, или идёт загрузка. Если код может выйти из обработчика, не показав ничего, рано или поздно он так и сделает.
function write(userId: string) { start(async () => { try { const result = await openConversation(userId); if (result.ok && result.conversationId) { // Обычный переход, а не router.push: тот, вызванный сразу // после серверного действия, молча не срабатывал. window.location.assign( `/${locale}/account/messages/${result.conversationId}`, ); } else { setSearchNote(result.message ?? "Не удалось открыть переписку"); } } catch { // Действие может БРОСИТЬ, а не вернуть отказ — например, когда // истекла сессия. Без перехвата кнопка молча не делала бы ничего. setSearchNote( "Не получилось — возможно, истёк вход. Обновите страницу и войдите заново.", ); } });}