ESLint-plugin для React-эффектов: когда меньше — действительно лучше

#react#eslint#performance#typescript

Последние два года я наблюдаю интересный тренд: React-комьюнити массово протрезвело от useEffect. После лет холиваров “классовые vs функциональные компоненты” мы наконец разобрались, что проблема не в парадигме, а в злоупотреблении side effects. На этом фоне выход eslint-plugin-react-you-might-not-need-an-effect v1.0.0 — отличный повод пересмотреть свои привычки.

Что не так с нашими эффектами

Проблема useEffect не в самом API, а в том, как мы его используем. Типичные кейсы, которые я встречаю в ревью:

  1. Эффекты-костыли для синхронизации состояния, которое можно выразить через композицию
  2. Подписки на внешние сторы через useEffect вместо useSyncExternalStore
  3. Каскады обновлений, когда один эффект триггерит другой, а тот — третий

Новый плагин ловит именно эти антипаттерны. Вот пример из его документации:

// ❌ До
function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() => {
    const updateState = () => setIsOnline(navigator.onLine);
    window.addEventListener('online', updateState);
    window.addEventListener('offline', updateState);
    return () => {
      window.removeEventListener('online', updateState);
      window.removeEventListener('offline', updateState);
    };
  }, []);
}

// ✅ После
function useOnlineStatus() {
  return useSyncExternalStore(subscribe, getSnapshot);
}

Что изменилось в v1.0.0:

Новое правило для внешних сторов

Правило no-external-store-subscription закрывает последний пробел относительно официальной React-документации. Оно заставляет задуматься: действительно ли вам нужен эффект для работы с внешним состоянием? В 90% случаев ответ — нет.

Особенно радует, что плагин учитывает контекст:

Меньше ложных срабатываний

Автор переработал детекцию переменных, что снизило количество false positives для:

На практике это значит, что теперь можно добавить плагин в legacy-проект без сотни исключений.

Технические улучшения

Миграция на TypeScript и сборку через tsdown — это не просто “мы тоже используем модный инструмент”. В данном случае это дало:

Лично для меня главный сюрприз — совместимость с Oxlint. Если вы ещё не пробовали этот Rust-аналог ESLint, теперь можно тестировать новые правила без полного перехода.

Где это имеет смысл

Плагин идеально впишется в:

А вот где я бы пока воздержался:

Попробуйте добавить его с минимальным конфигом:

// eslintrc.js
module.exports = {
  plugins: ['react-you-might-not-need-an-effect'],
  rules: {
    'react-you-might-not-need-an-effect/no-external-store-subscription': 'warn'
  }
}

После недели использования вы удивитесь, сколько эффектов в вашем коде на самом деле лишние. Мой рекорд — 40% удалённых useEffect в одном из проектов без изменения функциональности.


Источник: https://github.com/nickjvandyke/eslint-plugin-react-you-might-not-need-an-effect