Головна / Статті / Розуміння користувацьких гаків React: повторне використання логіки без спільного стану

Розуміння користувацьких гаків React: повторне використання логіки без спільного стану

Дізнайтеся, що таке користувацькі хуки React, як вони дозволяють виділяти та обмінюватися логікою зі станом між компонентами, та які поширені помилки варто уникати під час їх створення.

1281 слів

Вступ

Чи траплялося з вами коли-небудь писати однакову пару useState та useEffect у трьох різних компонентах, змінюючи лише назви змінних? Майже кожен розробник React стикається з цим у певний момент. Код працює нормально, але це означає, що ідентична логіка дублюється по всьому кодбазу, і кожна копія з часом починає відрізнятися через окремі зміни.

Саме цю проблему і було створено для вирішення спеціальні хуки в React. документація React на цю тему пояснює, що перенесення поведінки компонента в окрему, багаторазово використовувану функцію дозволяє різним частинам додатку мати спільну поведінку зі станом, замість того щоб постійно копіювати основну реалізацію. У цій частині статті розглядається, що таке насправді спеціальні хуки, як вони працюють у реальному коді, а також переваги та недоліки, які потрібно знати перед створенням власних хуків.

Що таке спеціальні хуки React

По суті, користувацький хук — це просто функція JavaScript, яка дотримується одного суворого правила найменування: її ім’я має починатися з use. Усередині неї можна викликати інші хуки, такі як useState чи useEffect, а також повертати ті значення чи функції, які потрібні компоненту, що її викликає. Сам React не надає цій функції жодних особливих умов під час виконання — префікс use є суто конвенційним, але він є необхідним, оскільки дозволяє React правильно застосовувати правила хуків та допомагає іншим розробникам миттєво зрозуміти, для чого призначена функція.

Користувацькі хуки проти звичайних функцій

Стандартна функція-допоміжний елемент може виконувати багато корисних завдань, але їй заборонено викликати інші хуки, оскільки вона знаходиться поза механізмом відображення React. Власний хук не має такої обмеження. Саме в цьому його перевага: ви можете об’єднати поведінку, що залежить від стану — відстеження прапорця завантаження, прослуховування подій браузера чи щось подібне — у щось повторно використовуване, що все одно легко інтегрується в життєвий цикл компонентів React.

Як працюють власні хуки React на практиці

Конкретний приклад пояснює це набагато швидше, ніж будь-яке абстрактне пояснення.

Витягування логіки з компонента

function StatusBadge() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const goOnline = () => setIsOnline(true);
    const goOffline = () => setIsOnline(false);

    window.addEventListener('online', goOnline);
    window.addEventListener('offline', goOffline);

    return () => {
      window.removeEventListener('online', goOnline);
      window.removeEventListener('offline', goOffline);
    };
  }, []);

  return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}

Замість цього ви можете перенести цю логіку у окремий кастомний хук, і з того моменту будь-який компонент, якому потрібен статус, просто викликає його:

function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const goOnline = () => setIsOnline(true);
    const goOffline = () => setIsOnline(false);

    window.addEventListener('online', goOnline);
    window.addEventListener('offline', goOffline);

    return () => {
      window.removeEventListener('online', goOnline);
      window.removeEventListener('offline', goOffline);
    };
  }, []);

  return isOnline;
}

// Usage in any component:
function StatusBadge() {
  const isOnline = useOnlineStatus();
  return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}

Жодному з компонентів більше не потрібно самостійно налаштовувати слухачі подій — кожен просто запитує useOnlineStatus про поточне значення.

Обмін логікою стану без обміну самим станом

Це деталь, яка часто здивовує новачків: кастомний хук ділиться поведінкою, а не самим станом. Якщо два окремі компоненти кожен викликає useOnlineStatus, кожен з них отримує власну приватну копію цього стану. Вони виконують ідентичну логіку, але фактичні значення в кожному компоненті є абсолютно незалежними — між ними немає спільного чи пов’язаного стану.

Ключові переваги використання кастомних хуків у React

  • Можливість повторного використання між компонентами: Як тільки логіка розміщується всередині хука, жодному компоненту в додатку не потрібно копіювати жодного рядка, щоб її використати, і це гарантує, що поведінка залишатиметься послідовною всюди, де вона використовується.
  • Чистіші та зрозуміліші компоненти: Виведення логіки, яка керує станом, з компонента означає, що решта коду компонента майже не містить проблем з управлінням станом, що значно прискорює його розуміння для новачків за один погляд.
  • Простіше тестування ізольовано: Виведену логіку можна тестувати абсолютно окремо від будь-якого компонента, який її використовує, тобто її потрібно перевіряти лише один раз, а не повторно кожного разу, коли змінюється компонент-споживач.
  • Доступ до досвідчених фахівців: Створення гаків, які справді можна використовувати знову та знову — а не просто логіки під новою назвою, скопійованої та вставленої з додаванням префіксу use — вимагає справжньої обізнаності з основними патернами React. Команди, які хочуть, щоб це було належним чином вирішене з самого початку, іноді шукають фахівців поза межами власного персоналу та залучають спеціалістів з ReactJS, чий досвід допомагає зберігати стабільність проектування гаків навіть під час його розширення.
  • Поширені помилки, яких слід уникати

    Навіть гаки, написані з добрими намірами, можуть призвести до проблем кількома передбачуваними способами.

    • Порушення правил використання хуків: Виклик хука всередині умовного оператора, у циклі чи з звичайної функції замість компонента чи іншого хука заважає React підтримувати консистентність стану під час кожного оновлення інтерфейсу. Як наслідок з’являється дивна, періодична помилка, причину якої важко виявити.
    • Надмірне навантаження одного хука: Загортання у процес валідації форм, звернень до мережі та керування станом інтерфейсу в один користувацький хук ускладнює його тестування, повторне використання та розуміння порівняно з ситуацією, коли ці функції розподілені між двома-трьома меншими, більш спеціалізованими хуками.
  • Вилучення логіки, яку не потрібно було вилучати: Не кожен виклик useState заслуговує на те, щоб стати окремим хуком. Якщо шматок логіки використовується лише в одному місці, його вилучення лише додає додатковий рівень непрямості без жодної реальної користі.
  • Забування про мемоїзацію там, де це важливо: Коли користувацький хук повертає функції чи об’єкти, не мемоїзувавши їх належним чином, компоненти, які використовують цей хук, можуть змушені бути перероблені зайвий раз. Така втрата продуктивності є непомітною та легко проходить повз під час звичайних тестувань.
  • Висновок

    Кастомні хуки в React не лише допомагають уникати повторення коду, а й є справжнім механізмом для підтримки кохерентності та послідовності у постійно розширюваній базі коду. Як тільки команда розвиває навичку виявлення логіки, яку варто виділити у окремий хук, складність компонентів зазвичай зменшується, баги стають легкішими для виявлення, а поведінка залишається однаковою в усьому додатку, замість того щоб поступово відрізнятися між компонентами, які мали б працювати однаково. У міру того, як додатки на React продовжують зростати за масштабом та складністю, розуміння того, коли та як створити надійний кастомний хук, перетворюється на базову навичку, а не щось, призначене лише для досвідчених розробників.

    Якщо ваша команда працює з кодовою базою, наповненою дубльованою логікою, та хоче надати їй справжньої структури, можливо, варто звернутися до компанії з розробки на React js, яка вже керувала подібними процесами оптимізації на інших великих проектах.

    Пов’язані матеріали

  • React Query та Redux: Переосмислення стану сервера у великих додатках — Дізнайтеся, чому додаток для чату у продакшені використовував TanStack Query замість Redux для керування даними сервера, та де все ще знаходить своє місце Redux у сучасній архітектурі React.
  • Як уникнути „тихих“ багів стану через зміни в посиланнях у JavaScript — Дізнайтеся, чому зміна об’єктів та масивів через посилання порушує процес перерендерингу в React, чому операція spread копіює лише поверхневий рівень даних, та як безпечно створювати глибокі клони стану.
  • Створення ментальної моделі для React: узгодження, стан та хуки — Дізнайтеся про логіку, яка стоїть за основними концепціями React — узгодженням, компонентами, пропсами, станом та хуками, — щоб розвинути інтуїцію замість запам’ятовування API.