В React хуки є потужним інструментом для управління побічними ефектами у компонентах. Серед найпоширеніших виділяють useEffect, useLayoutEffect та useEffectEvent. Кожен з них має своє призначення, тому важливо правильно підібрати хук для конкретної задачі.
Хук useEffect
useEffect є основоположним хуком в React, призначеним для виконання побічних ефектів, таких як взаємодія з DOM, асинхронні операції чи отримання даних у функціональних компонентах. Він являє собою функцію, що приймає два аргументи: функцію ефекту та масив залежностей.
Функція ефекту містить код, що виконує побічний ефект, а масив залежностей визначає, коли ця функція повинна бути викликана. Якщо масив залежностей порожній, функція ефекту спрацює лише один раз під час першого рендерингу компонента. В іншому випадку, вона буде викликана щоразу, коли зміниться будь-яке значення в масиві залежностей.
Ось приклад використання useEffect для отримання даних:
import React from "react"; function App() { const [data, setData] = React.useState([]); React.useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts") .then((response) => response.json()) .then((data) => setData(data)); }, []); return ( <div className="app"> {data.map((item) => ( <div key={item.id}>{item.title}</div> ))} </div> ); } export default App;
У цьому прикладі компонент App отримує дані з API JSONPlaceholder за допомогою useEffect. Функція ефекту виконує запит на отримання даних, аналізує JSON-відповідь і зберігає дані у стані компонента.
Після цього, за допомогою стану даних, компонент відображає заголовок кожного елемента у вигляді списку.
Характеристики використання useEffect
- Підтримка асинхронності: дозволяє виконувати асинхронні операції, такі як отримання даних.
- Виконання після рендерингу: useEffect виконує ефекти після того, як компонент вже відрендерився, що запобігає блокуванню інтерфейсу користувача.
- Очищення: надає механізм для очищення ресурсів за допомогою повернення функції. Це корисно при роботі зі слухачами подій або підписками.
Хук useLayoutEffect
useLayoutEffect схожий на useEffect, але виконується синхронно після всіх змін в DOM. Це означає, що він спрацьовує до того, як браузер оновлює екран. Це робить його придатним для задач, де потрібен точний контроль над макетом та стилями DOM, як вимірювання розмірів елемента, його зміна або анімація.
Нижче наведено приклад використання useLayoutEffect для зміни ширини кнопки:
import React from "react"; function App() { const button = React.useRef(); React.useLayoutEffect(() => { const { width } = button.current.getBoundingClientRect(); button.current.style.width = `${width + 12}px`; }, []); return ( <div className="app"> <button ref={button}>Натисни мене</button> </div> ); } export default App;
У цьому прикладі ширина елемента кнопки збільшується на 12 пікселів за допомогою useLayoutEffect. Це гарантує, що зміна ширини буде видима до відображення кнопки на екрані.
Характеристики useLayoutEffect
- Синхронність: виконується синхронно, що може блокувати інтерфейс користувача, якщо операція складна.
- Взаємодія з DOM: ідеально підходить для читання та запису в DOM, особливо якщо потрібні зміни перед перемалюванням браузера.
Хук useEffectEvent
useEffectEvent – це хук, який розв’язує проблеми залежностей хука useEffect. Масив залежностей useEffect може бути досить складним і вимагає додавання значень, які іноді є зайвими.
Наприклад:
import React from "react"; function App() { const connect = (url) => { }; const logConnection = (message, loginOptions) => { }; const onConnected = (url, loginOptions) => { logConnection(`Connected to ${url}`, loginOptions); }; React.useEffect(() => { const device = connect(url); device.onConnected(() => { onConnected(url); }); return () => { device.disconnect(); }; }, [url, onConnected]); return <div></div>; } export default App;
Цей код демонструє компонент, що керує підключенням до зовнішньої служби. Функція connect встановлює з’єднання з вказаною URL-адресою, а logConnection реєструє деталі з’єднання. onConnected викликає logConnection після успішного підключення.
useEffect викликає connect та встановлює зворотній виклик onConnected, який викликає logConnection. Повертається функція очищення для відключення пристрою при розмонтуванні компонента.
Масив залежностей містить змінну url і функцію onConnected. Компонент App створюватиме нову функцію onConnected при кожному рендерингу, що призведе до циклічного запуску useEffect та повторних рендерингів.
Є кілька шляхів для вирішення цієї проблеми, але найефективнішим, без додавання зайвих залежностей, є використання useEffectEvent.
import React from "react"; function App() { const connect = (url) => { }; const logConnection = (message, loginOptions) => { }; const onConnected = React.useEffectEvent((url, loginOptions) => { logConnection(`Connected to ${url}`, loginOptions); }); React.useEffect(() => { const device = connect(url); device.onConnected(() => { onConnected(url); }); return () => { device.disconnect(); }; }, [url]); return <div></div>; } export default App;
Обгортаючи функцію onConnected useEffectEvent, useEffectEvent завжди може читати актуальні значення параметрів message та loginOptions перед тим, як передати їх useEffect. Таким чином, useEffect не залежить від функції onConnected та її значень.
useEffectEvent корисний, коли потрібно, щоб useEffect залежав від певного значення, але побічний ефект ініціює події, що вимагають інших значень, які не є бажаними залежностями useEffect.
Характеристики useEffectEvent
- Найкраще підходить для побічних ефектів, що викликані подіями.
- useEffectEvent не працює з обробниками подій, такими як onClick, onChange і т.д.
useEffectEvent все ще є експериментальним та недоступний в React 18.
Коли використовувати який хук?
Кожен з описаних хуків призначений для різних ситуацій:
- Отримання даних: useEffect є найкращим вибором.
- Прямі маніпуляції з DOM: useLayoutEffect підходить для синхронних змін DOM перед перемалюванням.
- Нескладні операції: useEffect підходить для операцій, що не блокують інтерфейс користувача.
- Побічні ефекти, керовані подіями: використовуйте useEffectEvent для обгортання подій та useEffect для запуску ефектів.
Ефективне управління побічними ефектами
Розуміння відмінностей між useEffect, useLayoutEffect та useEffectEvent є ключовим для ефективного управління побічними ефектами та маніпуляціями DOM у React. Правильний вибір хука, виходячи зі специфічних вимог та наслідків, дозволить створити зручні для користувача програми.