Именуйте функции в useEffect: практика для читаемого кода в React

useEffect — один из основных хуков в React для работы с побочными эффектами. Но на практике код с несколькими эффектами часто становится трудночитаемым. Разработчик Neciu Dan предлагает простое решение: давать функциям внутри useEffect осмысленные имена.

Имена функция — это вопрос читаемости и понятности

  • Читаемость. Код становится самодокументируемым — название функции объясняет её назначение.
  • Отладка. В стеке ошибок отображается имя функции, проще найти проблемный эффект.
  • Рефакторинг. Сложный эффект легче вынести в кастомный хук, так как функция уже обособлена.
  • Командная работа. Коллегам не нужно вникать в детали реализации, чтобы понять логику компонента.

Пример из практики

Компонент должен:

  • загружать список продуктов при смене категории;
  • подписываться на обновления выбранного продукта;
  • логировать аналитические события.

Без названия

Функция внутри остаётся анонимной. В компоненте с несколькими эффектами приходится изучать тело каждой функции, чтобы понять её назначение. Это замедляет отладку и код-ревью.

function InventorySync({ warehouseId, locationId, onStockChange }) {
  const [stock, setStock] = useState<StockLevel[]>([]);
  const [connected, setConnected] = useState(false);
  const prevLocationId = useRef(locationId);

  useEffect(() => {
    const ws = new WebSocket(`wss://inventory.api/ws/${warehouseId}`);
    ws.onopen = () => setConnected(true);
    ws.onclose = () => setConnected(false);
    ws.onmessage = (event) => {
      const update = JSON.parse(event.data);
      setStock(prev => prev.map(s =>
        s.sku === update.sku ? { ...s, quantity: update.quantity } : s
      ));
    };
    return () => ws.close();
  }, [warehouseId]);

  useEffect(() => {
    if (!connected) return;
    fetch(`/api/warehouses/${warehouseId}/stock?location=${locationId}`)
      .then(res => res.json())
      .then(setStock);
  }, [warehouseId, locationId, connected]);

  useEffect(() => {
    if (prevLocationId.current !== locationId) {
      setStock([]);
      prevLocationId.current = locationId;
    }
  }, [locationId]);

  useEffect(() => {
    if (stock.length > 0) {
      onStockChange(stock);
    }
  }, [stock, onStockChange]);

  // ... render
}

С названием

Название функции сразу объясняет, что делает эффект.

function InventorySync({ warehouseId, locationId, onStockChange }) {
  const [stock, setStock] = useState<StockLevel[]>([]);
  const [connected, setConnected] = useState(false);
  const prevLocationId = useRef(locationId);

  useEffect(function connectToInventoryWebSocket() {
    const ws = new WebSocket(`wss://inventory.api/ws/${warehouseId}`);
    ws.onopen = () => setConnected(true);
    ws.onclose = () => setConnected(false);
    ws.onmessage = (event) => {
      const update = JSON.parse(event.data);
      setStock(prev => prev.map(s =>
        s.sku === update.sku ? { ...s, quantity: update.quantity } : s
      ));
    };
    return () => ws.close();
  }, [warehouseId]);

  useEffect(function fetchInitialStock() {
    if (!connected) return;
    fetch(`/api/warehouses/${warehouseId}/stock?location=${locationId}`)
      .then(res => res.json())
      .then(setStock);
  }, [warehouseId, locationId, connected]);

  useEffect(function resetStockOnLocationChange() {
    if (prevLocationId.current !== locationId) {
      setStock([]);
      prevLocationId.current = locationId;
    }
  }, [locationId]);

  useEffect(function notifyParentOfStockUpdate() {
    if (stock.length > 0) {
      onStockChange(stock);
    }
  }, [stock, onStockChange]);

  // ... render
}

Этот вариант проще читать при навигации по файлу компонента.

Когда применять паттерн

Именование эффектов имеет смысл, если:

  • логика эффекта занимает больше нескольких строк;
  • в компоненте несколько useEffect;
  • назначение эффекта неочевидно из зависимостей.

Для простых эффектов (например, обновление заголовка документа по одной переменной) выгода может быть минимальной. Но в реальных проектах именованные эффекты окупаются.

Итог

Именование функций в useEffect — практика с минимальными затратами и заметным эффектом. Она соответствует принципу «код пишут для людей, а не для компьютеров». Компоненты становятся проще для чтения, отладки и поддержки.


Источник: блог-пост Neciu Dan «Start naming your useEffect functions, you will thank me later».

Фото аватара

Владимир Анохин

Разработчик плагина Shortcodes Ultimate про WordPress, популярного бесплатного инструмента. Этот плагин позволяет пользователям легко добавлять на сайты визуальные и функциональные элементы, такие как кнопки, слайдеры, карусели и другие, с помощью шорткодов.

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *