Правило было не задано вовсе: плагин eslint-plugin-react-hooks подключает
профиль @microsoft/eslint-config-spfx/lib/profiles/react, но правил из него
не включает. Теперь в .eslintrc.js явно заданы rules-of-hooks (error) и
exhaustive-deps (warn); сборка проходит с нулём предупреждений.
Что реально чинилось, а не затыкалось:
- shared/useStableCallback.ts — обёртка с неизменной ссылкой над колбэком-пропом
(аналог будущего useEffectEvent). Ссылка стабильна, внутри всегда актуальная
версия колбэка, поэтому её можно честно класть в зависимости.
- onCodeLoaded во всех forms/*/*View.tsx и *Form.tsx идёт в эффект загрузки
через эту обёртку: просто дописать проп в зависимости нельзя — заявка
перезапрашивалась бы на каждый рендер родителя.
- useRequestSubmit: run стабилизирован (useCallback + savingRef вместо чтения
состояния), возвращаемый объект мемоизирован. Формы берут из него стабильный
setError и указывают в зависимостях его, а не submit целиком.
- shared/usePersistedQuery.ts (useRoutedQuery) — было устаревшее замыкание:
эффект навсегда запоминал первую версию onQueryChange, а та замкнута на route
на момент монтирования, то есть набранный запрос мог уехать в маршрут чужого
раздела. Теперь зовётся актуальная версия.
- propertyPane/DebugUserField.tsx — то же самое с onResolved.
- Формы: в эффект "новая заявка по умолчанию на себя" дописан context
(единственный экземпляр на жизнь веб-части, лишних перезапусков не даёт),
в ReferralForm ещё и мемоизированный approval.
- RequestsTableView: dataKey в зависимости (он и так выводится из view/
statusFilter/debouncedQuery, которые там уже есть).
Осознанные отступления оставлены с объяснением ПОЧЕМУ: useMatrixEditor (момент
перечитывания матрицы задаёт вызывающий через reloadKey), companiesFieldValue
в RecruitingHire/RecruitingSelection.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
useMemo с attachmentUrls стоял ПОСЛЕ `if (loading) return` — на первом
рендере (загрузка) он не вызывался, на втором вызывался, порядок хуков
менялся, и React ронял компонент с #310 «rendered more hooks than during
the previous render». Карточка заявки на услуги не открывалась вообще.
Перенёс расчёт выше ранних выходов.
Заодно включил `react-hooks/rules-of-hooks` (error) — плагин давно в
зависимостях и в коде есть eslint-disable для exhaustive-deps, то есть
правила подразумевались, но в .eslintrc их забыли объявить. По остальному
коду правило даёт 0 нарушений, так что этот баг был единственным.
`exhaustive-deps` пока оставил выключенным: на текущем коде это 16
предупреждений, их разбор — отдельная задача, а не довесок к фиксу.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>