React компонентна архітектура побудована на фундаментальному принципі функціонального програмування: чисті функції. Але що саме є чистими функціями і чому вони такі важливі для створення надійних React додатків? Давайте розглянемо на практичних прикладах і простих аналогіях.
Що робить функцію чистою? 🤔
Чиста функція дотримується двох основних правил:
- Вона займається лише своєю справою: Функція не змінює жодних змінних або об'єктів, які існували до її виклику.
- Ті самі вхідні дані — ті самі вихідні: За тих самих вхідних даних функція завжди повертає той самий результат.
Уявіть чисту функцію як надійну кавову автомат. Ви кладіть $2 (вхід), отримуєте звичайну каву (вихід). Кожного разу. Це не залежить від часу доби чи кількості кави, що була замовлена до цього — той самий вхід, той самий вихід.
Чисті функції в дії
Розглянемо просту математичну чисту функцію:
function double(number) {
return 2 * number;
}
Ця функція є чистою, тому що:
- Вона не змінює жодних зовнішніх змінних
- Вона завжди повертає той самий результат для тих самих вхідних даних
- Якщо ви передасте 3, ви завжди отримаєте 6.
React компоненти як чисті функції
У React компоненти повинні поводитись як чисті функції. Ось практичний приклад:
function Recipe({ drinkers }) {
return (
<div>
Boil {drinkers} cups of water.
Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.
Add {0.5 * drinkers} cups of milk to boil and sugar to taste.
</div>
);
}
Цей компонент є чистим, тому що:
- Він залежить лише від своїх пропсів (
drinkers
) - Завжди рендерить той самий результат для того самого значення
drinkers
- Він не змінює жодного зовнішнього стану
Коли функції стають нечистими: Нечисті компоненти
Розглянемо анти-патерн — нечистий компонент:
let guest = 0; // Зовнішня змінна 🚫
function Cup() {
guest = guest + 1; // Зміна зовнішнього стану — це погано!
return <div>Tea cup for guest #{guest}</div>;
}
Цей компонент нечистий, тому що:
- Він змінює зовнішню змінну (
guest
) - Кілька рендерів можуть дати різні результати
- Вихід є непередбачуваним
Чиста альтернатива
Ось як ми можемо виправити нечистий компонент:
function Cup({ guest }) {
return <div>Tea cup for guest #{guest}</div>;
}
function TeaSet() {
return (
<>
<Cup guest={1} />
<Cup guest={2} />
<Cup guest={3} />
</>
);
}
Тепер наш компонент чистий, тому що:
- Він залежить лише від своїх пропсів
- Повертає постійний результат
- Він не змінює жодного зовнішнього стану
Локальні мутації: Виключення з правила
Хоча змінювати зовнішній стан заборонено, ви можете змінювати змінні, створені всередині вашого компонента під час рендеру. Ось дійсно коректний приклад:
function TeaGathering() {
let cups = []; // Локальна змінна, створена під час рендеру
for (let i = 1; i <= 12; i++) {
cups.push();
}
return cups;
}
Це нормально, тому що:
- Масив
cups
створюється заново під час кожного рендеру - Жоден зовнішній стан не змінюється
- Мутації повністю обмежені всерединою компонента
Коли ми можемо порушити правила?
Іноді нам потрібно змінювати деякі речі — адже в цьому і полягає суть інтерактивних додатків! В React побічні ефекти повинні оброблятись у:
- Обробники подій (Event Handlers): Чудове місце для побічних ефектів
- useEffect: Коли потрібні побічні ефекти після рендеру
- Користувацькі хуки (Custom Hooks): Для повторного використання логіки побічних ефектів
Найкращі практики для чистих компонентів
- Зберігайте всі вхідні дані (props, state, context) незмінними
- Не змінюйте зовнішні змінні або об'єкти під час рендеру
- Повертайте постійний JSX для тих самих вхідних даних
- Обробляйте побічні ефекти в обробниках подій або useEffect
- Використовуйте локальні змінні для тимчасових обчислень
Висновок
Чисті функції є основою надійних React додатків.
Залишаючи ваші компоненти чистими, ви уникнете цілу категорію помилок, зробивши ваш додаток більш передбачуваним і легким для налагодження. Пам'ятайте: ті самі вхідні дані — ті самі вихідні, і жодних підступних змін зовнішнього світу!
Щасливого кодування! 🚀
Перекладено з: Understanding Pure Functions in React: A Developer’s Guide