НАЙКРАЩИЙ САЙТ ДЛЯ ВЕБ-РОЗРОБНИКІВ
React. W3Schools українською. Уроки для початківців

En

React хуки useEffect


Хук useEffect дозволяє виконувати побічні ефекти у ваших компонентах.

Декілька прикладів побічних ефектів: отримання даних, пряме оновлення DOM і таймери.

useEffect приймає два аргументи. Другий аргумент необов’язковий.

useEffect(<function>, <dependency>)


Візьмемо для прикладу таймер.

Приклад:

Використовуйте setTimeout() для підрахунку 1 секунди після початкового відтворення:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
setTimeout(() => {
  setCount((count) => count + 1);
}, 1000);
});

return <h1>Я відобразив {count} разів!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);

Виконати приклад »

Але зачекайте!! Він продовжує рахувати, хоча має рахуватися лише один раз!

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

Це не те, чого ми хочемо. Існує кілька способів контролювати появу побічних ефектів.

Ми завжди повинні включати другий параметр, який приймає масив. Додатково ми можемо передати залежності в useEffect у цьому масиві.

Приклад

1. Жодна залежність не пройдена:

useEffect(() => {
//Працює на кожному рендері
});

Приклад

2. Порожній масив:

useEffect(() => {
//Запускається лише на першому рендері
}, []);

Приклад

3. Реквізити (props) або значення стану (state):

useEffect(() => {
//Запускається на першому рендері
//І кожного разу, коли будь-яке значення залежності змінюється
}, [prop, state]);

Отже, щоб розв’язати цю проблему, запустіть цей ефект лише на початковому рендері.

Приклад:

Запустіть ефект лише на початковій візуалізації:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
setTimeout(() => {
  setCount((count) => count + 1);
}, 1000);
}, []); // <- додайте сюди порожні дужки

return <h1>Я відтворив {count} разів!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);

Виконати приклад »

Приклад:

Ось приклад хука useEffect, який залежить від змінної. Якщо змінна count оновиться, ефект запуститься знову:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function Counter() {
const [count, setCount] = useState(0);
const [calculation, setCalculation] = useState(0);

useEffect(() => {
setCalculation(() => count * 2);
}, [count]); // <- додайте сюди змінну лічильника

return (
<>
  <p>Count: {count}</p>
  <button onClick={() => setCount((c) => c + 1)}>+</button>
  <p>Calculation: {calculation}</p>
</>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Counter />);

Виконати приклад »

Якщо є кілька залежностей, їх слід включити в масив залежностей useEffect.


Очищення ефекту

Деякі ефекти потребують очищення, щоб зменшити витік пам’яті.

Тайм-аути, підписки, прослуховувачі подій та інші ефекти, які більше не потрібні, мають бути усунені.

Ми робимо це, додаючи функцію повернення в кінці хука useEffect.

Приклад:

Очистіть таймер у кінці хука useEffect:

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
let timer = setTimeout(() => {
setCount((count) => count + 1);
}, 1000);

return () => clearTimeout(timer)
}, []);

return <h1>Я відтворив {count} разів!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);

Виконати приклад »

Примітка: Щоб очистити таймер, нам потрібно було назвати його.


Перевірте себе за допомогою вправ

Вправа:

Що вам потрібно додати до другого аргументу хука useEffect, щоб обмежити його виконання лише на першому рендері?

import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function App() {
const [data, setData] = useState([]);

useEffect(() => {
setData(getData())
}, );

return <DisplayData data={data} />;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);