1. Що таке React?
- React — це JavaScript-бібліотека для створення користувацьких інтерфейсів. Основні характеристики:
-
Компонентний підхід: UI розбивається на окремі компоненти, які можна повторно використовувати.
-
Virtual DOM: Забезпечує ефективне оновлення інтерфейсу, мінімізуючи маніпуляції з реальним DOM.
-
Декларативність: Ви описуєте, як має виглядати UI в певному стані, а React забезпечує його відповідність.
-
Однонаправлений потік даних: Дані передаються згори донизу через props, що спрощує контроль за станом.
- React створений Facebook і широко використовується для розробки SPA (Single Page Applications).
2. Перерахуйте особливості React?
-
Компонентний підхід: Код розділений на багаторазові, незалежні компоненти.
-
Віртуальний DOM: Швидке оновлення інтерфейсу без прямого маніпулювання DOM.
-
Односпрямований потік даних: Дані передаються з батьківських компонентів у дочірні через пропси.
-
JSX: Розширення синтаксису JavaScript для написання UI у вигляді XML-подібного коду.
-
Стан і життєвий цикл: Компоненти можуть зберігати і управляти своїм станом.
-
React Hooks: Додають можливості роботи зі станом і побічними ефектами у функціональних компонентах.
-
Екосистема: Підтримує бібліотеки на кшталт React Router, Redux для розширення функціоналу.
-
SEO-френдлі (з Next.js): Серверний рендеринг для кращої індексації.
-
Мобільна розробка: React Native дозволяє створювати мобільні додатки на основі React.
-
Відкритий код: Активна підтримка спільноти.
3. Що таке Virtual DOM в React?
- Virtual DOM — це віртуальне представлення реального DOM, яке React використовує для ефективного оновлення інтерфейсу.
-
Рендеринг у Virtual DOM: При зміні стану або пропсів компонентів React оновлює Virtual DOM.
-
Diffing: React порівнює новий Virtual DOM зі старою версією, визначаючи мінімальний набір змін.
-
Оновлення реального DOM: Виявлені зміни застосовуються до реального DOM, зводячи до мінімуму кількість маніпуляцій.
-
Оптимізація оновлень DOM, що значно покращує продуктивність додатків.
-
Coming Soon... 😎
4. Навіщо потрібен атрибут key при рендері списків?
- Атрибут
key
використовується для ідентифікації елементів у списках під час рендеру.
-
Оптимізація оновлень: React використовує
key
для ефективного оновлення інтерфейсу, швидко визначаючи, які елементи змінити, додати або видалити. -
Запобігання зайвим рендерам:
key
допомагає уникнути перерендеру незмінених елементів. -
Збереження стану компонентів: Наприклад, якщо елемент списку містить форму,
key
дозволяє React зберігати її стан між оновленнями.
-
Значення
key
має бути унікальним серед братніх елементів. -
Найкраще підходять стабільні ідентифікатори (наприклад,
id
з бази даних). -
Не рекомендується використовувати індекс масиву як
key
, оскільки це може призвести до помилок при зміні порядку елементів.
const items = ["Apple", "Banana", "Cherry"];
return (
<ul>
{items.map((item, index) => (
<li key={item}>{item}</li> // Унікальний key для кожного елемента
))}
</ul>
);
5. Що таке JSX?
- JSX (JavaScript XML) — це синтаксис, який дозволяє писати структури UI у вигляді XML-подібного коду всередині JavaScript. JSX є розширенням JavaScript і використовується в React для опису, як виглядає інтерфейс.
- XML-подібний синтаксис: Нагадує HTML, але використовується у JavaScript.
const element = <h1>Hello, world!</h1>;
- Вбудований JavaScript: Ви можете писати JavaScript-код у фігурних дужках
{}
.
const name = "Alice";
const element = <h1>Hello, {name}!</h1>;
- Трансляція: JSX компілюється в звичайний JavaScript, використовуючи такі бібліотеки, як Babel.
const element = <h1>Hello</h1>;
// Перетворюється в:
const element = React.createElement("h1", null, "Hello");
- Атрибути: Використовуються як у HTML, але замість
class
пишетьсяclassName
, а замістьfor
—htmlFor
.
const input = <input type="text" className="input-field" />;
- JSX повертає дерево елементів: JSX-вираз може повертати лише один кореневий елемент. Використовуйте
<React.Fragment>
або порожній тег<>
для групування.
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
- Зручне створення UI-компонентів.
- Зрозумілий і читабельний синтаксис.
- Тісна інтеграція з JavaScript-логікою.
JSX не обов'язковий у React, але широко використовується через зручність і гнучкість.
6. Різниця між станом (state) та пропсами (props)?
Критерій | State | Props |
---|---|---|
Призначення | Зберігає внутрішній стан компонента. | Передає дані від батьківського компонента до дочірнього. |
Змінюваність | Може змінюватися всередині компонента. | Незмінні (read-only). |
Доступність | Доступний тільки в компоненті, де визначений. | Доступний у дочірньому компоненті через атрибути. |
Ініціалізація | Встановлюється в компоненті за допомогою useState або конструктора. |
Визначається батьківським компонентом. |
Область використання | Для збереження динамічних даних, що можуть змінюватися. | Для передачі фіксованих або динамічних даних. |
Хто керує? | Компонент, у якому state визначений. | Батьківський компонент. |
7. Що таке React Хуки (Hooks)?
- React Хуки (Hooks) — це функції, які дозволяють вам використовувати стан та інші можливості React без написання класів.
- useState — дозволяє додавати стан в функціональні компоненти.
const [state, setState] = useState(initialState);
- useEffect — дозволяє виконувати побічні ефекти (наприклад, запити до API або підписки) у функціональних компонентах.
useEffect(() => {
// код для ефекту
}, [dependencies]); // залежності
- useContext — доступ до значень контексту без необхідності використовувати компонент Consumer.
const value = useContext(MyContext);
- useRef — дозволяє створювати посилання на DOM-елементи або зберігати значення між рендерами без змін стану.
const myRef = useRef(initialValue);
- useReducer — альтернатива useState, зручна для управління складнішими станами через редуктори, подібно до Redux.
const [state, dispatch] = useReducer(reducer, initialState);
- useMemo — оптимізує обчислення значень, щоб уникнути непотрібних повторних обчислень.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- useCallback — повертає мемоізовану версію функції, щоб вона не створювалась знову при кожному рендері.
const memoizedCallback = useCallback(() => {
// функція;
}, [dependencies]);
-
Функціональні компоненти: Замість класових компонентів ви можете використовувати функціональні компоненти з хуками.
-
Покращена читабельність: Логіка можна розділити на декілька хуків, що зменшує кількість коду та підвищує модульність.
-
Перерозподіл логіки: Хуки дозволяють повторно використовувати логіку в різних компонентах без створення складних ієрархій.
8. Що таке контекст (Context)?
- Контекст (Context) в React — це механізм для передачі даних через дерево компонентів без необхідності передавати ці дані через пропси на кожному рівні.
- React.createContext() — використовується для створення контексту.
const MyContext = React.createContext(defaultValue);
- Provider — компонент, який надає значення контексту. Він обгортає частину дерева компонентів і передає значення вниз через value.
<MyContext.Provider value={}>
<YourComponent />
</MyContext.Provider>
- Consumer — компонент, який споживає значення контексту. Зазвичай використовує функцію як дочірній елемент, що отримує значення контексту.
<MyContext.Consumer>
{value => }
</MyContext.Consumer>
- useContext — хук, який дозволяє доступити значення контексту без необхідності використовувати Consumer.
const value = useContext(MyContext);
-
Коли є потреба передавати дані між компонентами на різних рівнях ієрархії (наприклад, тема, мова або користувач).
-
Коли вам не хочеться передавати пропси через кілька рівнів компонентів, що може ускладнити код.
// Створення контексту
const ThemeContext = React.createContext("light");
// Компонент, який надає значення контексту
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
}
// Компонент, який споживає значення контексту
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div>The current theme is {theme}</div>;
}
-
Зручність в передачі глобальних значень.
-
Покращує масштабованість програми, зменшуючи кількість переданих пропсів.
9. Що таке портал (Portal)?
- Портал (Portal) у React — це спосіб рендерити дочірні елементи в DOM-вузол, який знаходиться за межами DOM-ієрархії батьківського компонента.
- React забезпечує портали через метод
ReactDOM.createPortal
, який приймає два аргументи:
-
React-елемент, що потрібно рендерити.
-
Цільовий DOM-вузол, у який слід вставити елемент.
ReactDOM.createPortal(child, container);
-
child — React-елемент, який потрібно рендерити.
-
container — DOM-вузол, де елемент буде вставлено.
import React from "react";
import ReactDOM from "react-dom";
function Modal({ children }) {
return ReactDOM.createPortal(
<div className="modal">{children}</div>,
document.getElementById("modal-root") // Цільовий вузол
);
}
function App() {
return (
<div>
<h1>Основний контент</h1>
<Modal>
<p>Це контент модального вікна</p>
</Modal>
</div>
);
}
-
Модальні вікна.
-
Спливаючі підказки (tooltips).
-
Контекстні меню.
- Ієрархія подій:
- Хоча елемент рендериться поза ієрархією DOM, обробка подій відбувається відповідно до React-ієрархії компонентів. Наприклад, події onClick підніматимуться до батьківських компонентів React.
- Гнучкість: Портали дозволяють вставляти елементи в місця, які не вписуються в поточну структуру DOM.
- Легке управління "плаваючими" елементами.
- Збереження контексту React навіть за межами основної DOM-ієрархії.
10. Методи життєвого циклу компонента у React?
- Методи життєвого циклу компонента в React використовуються для управління різними етапами життя компонентів: створення, оновлення та видалення.
- Монтування (Mounting): Коли компонент додається в DOM.
-
constructor(): Ініціалізація стану та прив'язка методів.
-
static getDerivedStateFromProps(props, state): Оновлення стану перед рендером (рідко використовується).
-
render(): Рендерить JSX у віртуальний DOM.
-
componentDidMount(): Викликається одразу після додавання компонента в DOM. Використовується для запитів API, ініціалізації бібліотек.
- Оновлення (Updating): Коли змінюються пропси або стан.
-
static getDerivedStateFromProps(props, state): Викликається перед кожним рендером.
-
shouldComponentUpdate(nextProps, nextState): Контролює, чи потрібно повторно рендерити компонент. За замовчуванням повертає true.
-
render(): Виконується для оновлення віртуального DOM.
-
getSnapshotBeforeUpdate(prevProps, prevState): Отримує знімок перед змінами (наприклад, положення скролу).
-
componentDidUpdate(prevProps, prevState, snapshot): Викликається після оновлення. Використовується для повторних запитів або роботи з DOM.
- Розмонтування (Unmounting): Коли компонент видаляється з DOM.
- componentWillUnmount(): Використовується для очищення ресурсів (наприклад, таймерів, підписок).
- Обробка помилок (Error Handling): Коли компонент викликає помилку.
-
static getDerivedStateFromError(error): Дозволяє оновити стан після помилки.
-
componentDidCatch(error, info): Логування помилок.
Фаза | Метод | Опис |
---|---|---|
Монтування | constructor() |
Ініціалізація стану та налаштування. |
getDerivedStateFromProps() |
Оновлення стану перед рендером. | |
render() |
Рендеринг JSX у віртуальний DOM. | |
componentDidMount() |
Виконується після додавання в DOM. | |
Оновлення | getDerivedStateFromProps() |
Оновлення стану перед рендером. |
shouldComponentUpdate() |
Визначає, чи потрібен повторний рендер. | |
render() |
Оновлює віртуальний DOM. | |
getSnapshotBeforeUpdate() |
Отримує знімок стану перед оновленням. | |
componentDidUpdate() |
Виконується після оновлення. | |
Розмонтування | componentWillUnmount() |
Очищення ресурсів перед видаленням. |
Обробка помилок | getDerivedStateFromError() |
Оновлює стан у разі помилки. |
componentDidCatch() |
Логування помилок. |
У функціональних компонентах замість методів життєвого циклу використовують хуки:
-
useEffect
замінюєcomponentDidMount
,componentDidUpdate
,componentWillUnmount
. -
useState
для управління станом.
11. Яка історія еволюції React?
- Ось коротка історія еволюції React:
- 2011
- React створений у Facebook для внутрішніх потреб. Його розробив інженер Джордан Волке, щоб вирішити проблему ефективного оновлення інтерфейсу.
- 2013
- Facebook випустив React як open-source бібліотеку. Спочатку спільнота зустріла її скептично через використання JSX, який здавався незвичним.
- 2015
-
Випущено React 0.14: розділено React і ReactDOM, що зробило бібліотеку більш модульною.
-
Facebook представив React Native, що дозволило створювати нативні мобільні додатки за допомогою React.
- 2016
- Випущено React 15. Основні оновлення торкнулися покращення продуктивності через новий рендеринг-движок.
- 2017
-
Випущено React 16 (Fiber). Fiber став новою архітектурою, що забезпечила покращену продуктивність та підтримку асинхронного рендерингу.
-
Додано підтримку порталів і помилкових кордонів (Error Boundaries).
- 2018
- Facebook представив React Hooks, які дозволили використовувати стан і методи життєвого циклу у функціональних компонентах. Це стало революцією у способі створення компонентів.
- 2019
-
Випущено React 16.8 з офіційною підтримкою хуків.
-
Покращено ефективність Concurrent Mode (експериментально).
- 2020
-
Випущено React 17. Головна мета — спрощення поступового оновлення React у великих проектах.
-
Додано підтримку сучасних інструментів і нових можливостей для роботи з JSX.
- 2022 і далі
- Випущено React 18. Головними нововведеннями стали Concurrent Rendering, новий API useTransition та useDeferredValue, які покращують продуктивність у динамічних додатках.
-
Від класових компонентів до функціональних з хуками.
-
Підтримка серверного рендерингу (SSR).
-
Concurrent Mode для плавного оновлення інтерфейсу.
-
Інтеграція React із мобільною розробкою через React Native.
React залишився популярним завдяки високій продуктивності, зручності використання та постійній підтримці від Facebook.
12. Які основні функції React?
- Декларативний підхід
- React дозволяє створювати інтерактивний інтерфейс, описуючи, як він повинен виглядати, а бібліотека сама оптимізує оновлення DOM.
- Компонентна структура
- Додаток будується з незалежних, багаторазових компонентів, які спрощують розробку, тестування та підтримку.
- Віртуальний DOM
- React використовує Virtual DOM для ефективного оновлення реального DOM, що значно покращує продуктивність.
- Односпрямований потік даних
- Дані передаються від батьківських компонентів до дочірніх через props, що спрощує управління станом.
- Хуки (Hooks)
- Дозволяють використовувати стан і методи життєвого циклу у функціональних компонентах.
- JSX
- Розширення JavaScript для опису UI в синтаксисі, схожому на HTML.
- React Native
- Можливість створювати нативні мобільні додатки з використанням тих самих принципів, що і для вебу.
- Екосистема
- Великий набір бібліотек та інструментів, таких як React Router, Redux, Context API.
- Підтримка серверного рендерингу (SSR)
- Дозволяє оптимізувати SEO та прискорювати початкове завантаження сторінок.
- Управління станом
- За допомогою useState, Context API, Redux чи інших бібліотек.
Ці функції роблять React потужною і гнучкою бібліотекою для створення сучасних додатків.
13. Яка різниця між елементом і компонентом?
Критерій | Елемент | Компонент |
---|---|---|
Визначення | Об'єкт, що описує, як має виглядати інтерфейс. | Функція або клас, який повертає React-елементи. |
Тип | Нероздільний (immutable). | Багаторазовий і може мати стан (state). |
Синтаксис створення | React.createElement або JSX (<div /> ). |
Функція або клас (function MyComponent() {} або class MyComponent extends React.Component {} ). |
Призначення | Представляє окремий вузол у DOM. | Інкапсулює логіку та структуру інтерфейсу. |
Можливість використання | Використовується для створення UI на базовому рівні. | Використовується для побудови складних структур із бізнес-логікою. |
Приклад | <h1>Hello</h1> |
function Hello() { return <h1>Hello</h1>; } |
- Елемент — це "будівельний блок", а компонент — "конструктор" для створення складних інтерфейсів.
14. Як створити компоненти в React?
- Функціональний компонент
- Це проста функція, яка повертає React-елементи.
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Використання:
<Greeting name="John" />;
- Класовий компонент
- Це клас, який успадковується від React.Component і обов’язково має метод render.
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
// Використання:
<Greeting name="John" />;
-
Функціональні компоненти простіші та краще підходять для компонентів без стану.
-
Класові компоненти використовуються для складніших компонентів із власним станом або методами життєвого циклу.
Примітка: Сучасний підхід передбачає використання функціональних компонентів із хуками замість класових.
15. Коли використовувати компонент класу замість функціонального компонента?
- Класові компоненти використовувалися, коли потрібна була одна або кілька з цих функцій:
-
Робота зі станом (state): Раніше функціональні компоненти не підтримували локальний стан, тому використовували класи для цього. Сьогодні хуки (useState, useReducer) дозволяють функціональним компонентам працювати зі станом.
-
Методи життєвого циклу: Класи забезпечували доступ до методів, таких як componentDidMount, componentDidUpdate, componentWillUnmount, для управління компонентом на різних етапах його існування. Зараз це вирішується хуком useEffect.
-
Обробка складної логіки: Якщо логіка потребувала кількох методів і доступу до властивостей через this, класи виглядали логічним вибором. Сучасний підхід — хуки, які дозволяють інкапсулювати логіку.
- Починаючи з React 16.8, функціональні компоненти з хуками замінили потребу у класових компонентах. Тому в нових проєктах перевагу варто віддавати функціональним компонентам. Класи використовуються лише для підтримки застарілого коду.
16. Що таке чисті компоненти (Pure Components)?
- Чисті компоненти (Pure Components) — це спеціальні класові компоненти React, які автоматично оптимізують рендеринг. Вони реалізують поверхневе порівняння пропсів і стану, щоб запобігти зайвим оновленням, якщо значення пропсів або стану не змінилися.
- Чистий компонент створюється шляхом успадкування від React.PureComponent.
import React, { PureComponent } from "react";
class MyComponent extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
// Використання:
<MyComponent name="John" />;
-
Виконує поверхневе порівняння (
shallow comparison
) пропсів і стану у методіshouldComponentUpdate
. -
Якщо пропси та стан не змінилися, компонент не рендериться повторно.
-
Коли пропси та стан є простими структурами (примітивні значення або неглибокі об'єкти).
-
Для підвищення продуктивності в компонентах, які часто оновлюються.
- Глибоке порівняння:
PureComponent
не враховує зміни всередині вкладених об'єктів або масивів.
- Наприклад, якщо ви оновлюєте об'єкт, але посилання на нього залишається незмінним, компонент не оновиться.
this.setState({ data: { ...this.state.data, key: "new value" } }); // Обхідна
- Не працює з функціональними компонентами.
- Альтернатива: використовувати
React.memo
для оптимізації функціональних компонентів.
const MyComponent = React.memo(function MyComponent(props) {
return <h1>Hello, {props.name}!</h1>;
});
17. Що таке стан (state) у React?
- Стан (state) у React — це об'єкт, який використовується для зберігання даних, що можуть змінюватися з часом, і впливають на рендеринг компонента. Стан дозволяє компонентам React бути динамічними і реагувати на події, введення користувача тощо.
-
Локальний для компонента: Стан доступний тільки в тому компоненті, де він визначений.
-
Змінюється асинхронно: React об'єднує виклики setState для оптимізації рендерингу.
-
Ініціалізується в конструкторі (для класових компонентів) або через useState (у функціональних компонентах).
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
-
State — локальний для компонента і може змінюватися.
-
Props — передаються зовні і є незмінними (immutable).
18. Що таке пропси (props) в React?
- Пропси (props) в React — це об'єкт, який містить дані, що передаються від батьківського компонента до дочірнього. Вони використовуються для налаштування компонентів і є незмінними (immutable).
-
Передаються зверху вниз (унідіrectional data flow) — від батьківського компонента до дочірнього.
-
Незмінні — компонент не може змінювати отримані пропси.
-
Динамічні — значення пропсів можуть змінюватися, якщо змінюються дані в батьківському компоненті.
- У функціональному компоненті:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Використання:
<Welcome name="John" />;
- У класовому компоненті:
Копіювати;
Редагувати;
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
// Використання:
<Welcome name="Jane" />;
function App() {
return (
<div>
<Welcome name="Alice" />
<Welcome name="Bob" />
</div>
);
}
- Результат:
Hello, Alice!
Hello, Bob!
function Welcome({ name }) {
return <h1>Hello, {name}!</h1>;
}
function Welcome({ name = "Guest" }) {
return <h1>Hello, {name}!</h1>;
}
// Використання:
<Welcome />; // Виведе: Hello, Guest!
- Пропси забезпечують компонентам React гнучкість і можливість повторного використання.
19. Яка різниця між обробкою подій HTML і React?
Критерій | HTML | React |
---|---|---|
Прив’язка події | Вказується як атрибут: <button onclick="handler()"> . |
Використовується camelCase: <button onClick={handler}> . |
Тип функції | Посилання на глобальну функцію або рядок із JavaScript-кодом. | Прив’язка до функції компонента (зазвичай вказується як метод або стрілочна функція). |
Додавання слухачів подій | Обробники додаються вручну через addEventListener . |
React автоматично керує прив’язкою через віртуальний DOM. |
Контекст this |
Потрібно вручну встановлювати контекст, якщо використовується в класах. | React автоматично зберігає правильний контекст у функціональних компонентах. |
Стандартна поведінка | Необхідно явно викликати return false для припинення поведінки. |
Використовується event.preventDefault() для зупинки стандартної поведінки. |
Сумісність | Обробляє лише реальні DOM-події. | Використовує "SyntheticEvent", що є обгорткою над нативними подіями. |
Кросбраузерність | Потрібно вручну враховувати відмінності між браузерами. | React забезпечує кросбраузерну сумісність через SyntheticEvent. |
Прив’язка контексту | Часто вимагає використання bind . |
У класових компонентах потрібен bind , у функціональних — ні. |
<button onclick="alert('Clicked!')">Click me</button>
function handleClick() {
alert("Clicked!");
}
function App() {
return <button onClick={handleClick}>Click me</button>;
}
- React використовує обгортку над нативними подіями, яка нормалізує поведінку між різними браузерами та підвищує продуктивність.
20. Які ключові переваги використання React?
-
Швидкість: Завдяки Virtual DOM React мінімізує взаємодії з реальним DOM, що підвищує продуктивність.
-
Компонентний підхід: Код розбивається на багаторазово використовувані компоненти, що спрощує розробку та підтримку.
-
Одностороння передача даних: Потік даних у React відбувається в одному напрямку (зверху вниз), що полегшує дебагінг.
-
Велика спільнота: React має величезну екосистему бібліотек, інструментів і розширень.
-
Сумісність із мобільною розробкою: Використовуючи React Native, можна створювати кросплатформені мобільні додатки.
-
JSX: Синтаксис, який дозволяє писати JavaScript разом із HTML, що підвищує читабельність коду.
-
Підтримка хуків: Спрощення роботи зі станом та життєвим циклом у функціональних компонентах.
-
SEO-дружність: Серверний рендеринг за допомогою інструментів, таких як Next.js, покращує SEO-оптимізацію.
-
Гнучкість: React можна інтегрувати в будь-який проєкт або фреймворк без значних змін у коді.
-
React DevTools: Інструмент для налагодження, який дозволяє зручно аналізувати компоненти та стан додатка.
21. Що таке синтетичні події в React?
- Синтетичні події (Synthetic Events) у React — це обгортки для нативних DOM-подій, які надають однаковий інтерфейс для обробки подій на різних браузерах. React створює SyntheticEvent для кожної події, що дозволяє працювати з подіями в уніфікованому вигляді, забезпечуючи кросбраузерну сумісність і покращуючи продуктивність.
-
Кросбраузерність: SyntheticEvent абстрагує особливості роботи з подіями в різних браузерах, забезпечуючи однакову поведінку.
-
Оптимізація: SyntheticEvent використовує пул об'єктів, що дозволяє зменшити витрати на створення нових об'єктів подій.
-
Одноразове використання: Після обробки події об'єкт SyntheticEvent "повертається" в пул, і його не можна використовувати після цього. Для асинхронних операцій потрібно зберігати подію в окремій змінній.
-
Інтерфейс: SyntheticEvent має такі ж методи, як і стандартні нативні події (наприклад,
preventDefault()
,stopPropagation()
).
function handleClick(event) {
// SyntheticEvent має доступ до методу preventDefault()
event.preventDefault();
console.log("Button clicked!");
}
function App() {
return <button onClick={handleClick}>Click me</button>;
}
- У цьому прикладі event — це SyntheticEvent, який працює аналогічно до нативної події, але з покращеними можливостями.
22. Як оновити стан компонента?
- У React стан компонента оновлюється за допомогою методу
setState
у класових компонентах абоuseState
у функціональних компонентах.
-
Стан оновлюється через
this.setState()
. -
Приклад:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
-
Стан оновлюється через функцію, отриману з
useState
. -
Приклад:
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
- Асинхронність:
setState
іuseState
працюють асинхронно. Для оновлення стану на основі попереднього значення використовуйте функціональний підхід:
this.setState((prevState) => ({ count: prevState.count + 1 }));
setCount((prevCount) => prevCount + 1);
- Не оновлюйте стан напряму: Модифікація стану без використання
setState
абоuseState
не викликає повторний рендеринг.
23. Що таке вбудовані умовні вирази?
- Вбудовані умовні вирази в JavaScript (зокрема у React) — це механізми, що дозволяють вбудовувати умови безпосередньо в JSX для умовного рендерингу елементів або компонентів. Це дозволяє зробити код компактнішим і зручнішим для розуміння.
- Оператор умови (тернарний оператор): Це один із найпоширеніших способів для умовного рендерингу елементів в JSX. Він має такий синтаксис:
умова ? вираз_якщо_правда : вираз_якщо_неправда;
Приклад:
const isLoggedIn = true;
function App() {
return <div>{isLoggedIn ? <p>Welcome, User!</p> : <p>Please log in</p>}</div>;
}
- Логічний оператор AND (&&): Цей метод дозволяє відображати компонент або елемент тільки тоді, коли умова є true. Якщо умова не виконується, нічого не буде рендеритись.
Приклад:
const isUserAdmin = true;
function App() {
return <div>{isUserAdmin && <p>You have admin privileges</p>}</div>;
}
- У цьому випадку
<p>You have admin privileges</p>
буде відображено лише, якщоisUserAdmin
— цеtrue
.
- IF перед поверненням JSX: Можна також використовувати звичайні умовні оператори if перед поверненням JSX, коли умова має бути більш складною або коли потрібно виконати декілька умовних дій.
Приклад:
function App() {
let content;
if (isLoggedIn) {
content = <p>Welcome back!</p>;
} else {
content = <p>Please sign in.</p>;
}
return <div>{content}</div>;
}
-
Вбудовані умовні вирази дозволяють писати більш чистий і компактний код.
-
Вони покращують читаємість і зменшують використання додаткових умовних конструкцій.
- В React не можна використовувати інструкції
if
безпосередньо в JSX. Однак можна застосувати їх перед поверненням JSX.
24. Як обробляти події в React?
- В React обробка подій працює схоже на стандартний JavaScript, але з деякими відмінностями. Події в React є синтетичними, що означає, що вони мають абстракцію поверх реальних подій браузера, що забезпечує крос-браузерну сумісність.
-
Синтетичні події: Всі події в React обгорнуті в об'єкт SyntheticEvent, який є крос-браузерною реалізацією стандартних подій DOM. Це дозволяє обробляти події однаково в усіх браузерах.
-
Використання camelCase для подій: У React події записуються у форматі camelCase замість стандартного нижнього регістру (наприклад,
onClick
замістьonclick
). -
Передача функцій як обробників подій: Події в React обробляються за допомогою функцій, які передаються через атрибути компонентів.
import React, { Component } from "react";
class MyButton extends Component {
handleClick = () => {
alert("Button clicked!");
};
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
export default MyButton;
import React, { useState } from "react";
function MyButton() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return <button onClick={handleClick}>Clicked {count} times</button>;
}
export default MyButton;
-
Не потрібно використовувати
addEventListener
: В React немає необхідності вручну додавати або видаляти обробники подій. Це автоматично керується бібліотекою React. -
Збереження контексту в методах класових компонентів: Якщо методи класових компонентів використовуються як обробники подій, контекст (
this
) потрібно прив'язати або через стрілкові функції, або вручну в конструкторі.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
// Прив'язка методу
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<button onClick={this.handleClick}>
Clicked {this.state.count} times
</button>
);
}
}
- Передача параметрів у функцію обробника: Якщо потрібно передати додаткові аргументи в обробник події, можна використовувати стрілкові функції або функції з параметрами.
function MyButton({ label }) {
const handleClick = (event, label) => {
console.log(label);
};
return (
<button onClick={(event) => handleClick(event, label)}>{label}</button>
);
}
- Всі події, що відбуваються в React, працюють за принципом делегування подій, де один обробник подій реєструється для всього дерева компонентів і пропускається через React SyntheticEvent.
25. Що таке (key) prop і яка перевага його використання в масивах елементів?
- У React prop
key
використовується для ідентифікації кожного елементу в списках або масивах, щоб допомогти React ефективно керувати рендерами при зміні або оновленні елементів списку. Це важливо для оптимізації процесу рендерингу, особливо коли список змінюється (елементи додаються, видаляються або змінюються).
-
Унікальність: Кожен елемент у списку повинен мати унікальний
key
. Це дозволяє React відстежувати, які елементи змінюються, додаються або видаляються, а також зберігати їх стан між рендерами. -
Оптимізація рендерингу: Використання key дозволяє React мінімізувати кількість ререндерів, виконуючи тільки необхідні зміни в DOM. Без
key
, React має важчий час для відстеження змін, що призводить до повного повторного рендерингу списку, навіть якщо тільки один елемент змінився. -
Природа key: Prop
key
не передається в компонент, тому його не можна використовувати для відображення значень в UI. Це тільки інтерналізована властивість, що використовується React для відстеження елементів.
const items = ["apple", "banana", "cherry"];
function FruitList() {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li> // Важливо: використовувати унікальний key
))}
</ul>
);
}
-
Неправильне використання: Якщо у якості key використовувати неунікальні значення (наприклад, однаковий index), React не зможе коректно відстежувати зміни, і це призведе до помилок в рендерингу.
-
Ідеальний key: Зазвичай, якщо є унікальний ідентифікатор елемента (наприклад, id), він повинен бути використаний як key замість індексу масиву.
const items = [
{ id: 1, name: "apple" },
{ id: 2, name: "banana" },
{ id: 3, name: "cherry" },
];
function FruitList() {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li> // Краще використовувати унікальні id
))}
</ul>
);
}
-
Покращує продуктивність рендерингу.
-
Дозволяє React оптимально оновлювати тільки змінені елементи, а не весь список.
-
Забезпечує коректну обробку стану елементів при їх переміщенні, видаленні або оновленні.
Таким чином, використання key
є важливим для ефективної роботи з масивами елементів у React.
26. Що таке умовний рендеринг у React?
- Умовний рендеринг у React — це процес, при якому компонент рендерить різний вміст залежно від певних умов. Це дозволяє динамічно змінювати відображення компонента на основі стану, пропсів або інших факторів.
- Оператор
if
: Можна використовувати стандартний оператор if для вирішення, що рендерити.
function Greeting(props) {
if (props.isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please sign up.</h1>;
}
- Тернарний оператор: Часто використовують тернарний оператор для коротших умовних виразів.
function Greeting(props) {
return <h1>{props.isLoggedIn ? "Welcome back!" : "Please sign up."}</h1>;
}
- Логічне І (&&) для рендерингу: Можна використати логічний оператор
&&
, щоб рендерити елемент лише за умови, що вираз зліва від нього є істинним.
function Notifications(props) {
return (
<div>
{props.unreadMessages.length > 0 && (
<h2>You have {props.unreadMessages.length} unread messages.</h2>
)}
</div>
);
}
- Це працює так: якщо props.unreadMessages.length більше за 0, то відобразиться повідомлення, інакше нічого не буде відображено.
- Використання
return
з умовним оператором: Ви можете використовувати return для умовного рендерингу на основі різних умов, як в прикладі зif
або тернарним оператором.
-
Дозволяє динамічно змінювати вміст залежно від стану або пропсів.
-
Покращує гнучкість і можливість відображення різного контенту для різних користувачів або ситуацій.
function UserStatus(props) {
return (
<div>
{props.isLoggedIn ? (
<button onClick={props.logout}>Log Out</button>
) : (
<button onClick={props.login}>Log In</button>
)}
</div>
);
}
- Тут кнопка змінюється в залежності від того, чи користувач увійшов в систему.
27. Що таке React Fiber?
- React Fiber — це нова архітектура рендерингу в React, представлена з версії 16. Вона була розроблена для покращення продуктивності, підтримки асинхронного рендерингу та забезпечення більш гнучкого управління оновленнями UI.
- Покращена продуктивність:
- Fiber дозволяє React зберігати стан виконання рендеру, що дає можливість переривати і продовжувати рендеринг за потреби. Це важливо для великих додатків, де складні обчислення можуть уповільнювати рендеринг.
- Асинхронний рендеринг:
- React Fiber підтримує асинхронний рендеринг, що дозволяє виконувати рендеринг по частинах, покращуючи відгук додатку, особливо в складних інтерфейсах. Завдяки цьому можна виконувати рендеринг без блокування головного потоку.
- Пріоритет оновлень:
- Fiber дозволяє надавати пріоритет різним типам оновлень (наприклад, рендеринг анімацій може бути високим пріоритетом, а рендеринг змін стану — низьким). Це дозволяє React управляти складними оновленнями більш ефективно.
- Розбиття рендерингу на підзадачі:
- У старих версіях React всі зміни оброблялись в одному кроці. Fiber розбиває рендеринг на дрібніші підзадачі, що дозволяє React виконувати роботу поетапно і дає змогу обробляти інші важливі операції (наприклад, обробку подій) між етапами.
- Покращена підтримка анімацій та переходів:
- Завдяки асинхронному рендерингу, React може більш ефективно керувати анімаціями, що робить переходи між станами плавними та без затримок.
-
У старих версіях React весь процес рендерингу був синхронним: від початку до кінця. Це означало, що важкі обчислення блокували рендеринг інтерфейсу. У React Fiber рендеринг розділений на маленькі задачі, які можуть бути виконані асинхронно. Якщо необхідно, React може перервати одну задачу і продовжити виконання пізніше, не блокуючи інші операції (наприклад, оновлення UI або обробку подій).
-
Fiber дозволяє React:
-
Розподіляти виконання рендерингу для покращення продуктивності.
-
Реалізувати асинхронні оновлення UI.
-
Краще керувати пріоритетами та обробкою важких обчислень, що особливо важливо для складних інтерфейсів і додатків.
-
-
Покращення відгуку додатків.
-
Можливість обробляти важкі операції без затримок для користувача.
-
Краще управління анімаціями та переходами.
React Fiber — це внутрішнє оновлення, яке змінило спосіб, яким React працює з рендерингом, покращуючи загальну продуктивність додатків.
28. Як передаються дані між компонентами у React
- У React дані передаються між компонентами за ієрархією наступним чином:
-
Для передачі даних вниз використовується props. Батьківський компонент передає значення або функції через атрибути дочірньому компоненту.
-
Приклад:
function ParentComponent() {
const data = "Hello from Parent";
return <ChildComponent message={data} />;
}
function ChildComponent({ message }) {
return <p>{message}</p>;
}
-
message
передає значенняdata
в дочірній компонентChildComponent
. -
У дочірньому компоненті доступ до пропсів відбувається через параметр функції або
this.props
у класовому компоненті.
-
Дані передаються вгору за допомогою callback-функцій. Батьківський компонент передає функцію дочірньому, а той викликає її з потрібними даними.
-
Приклад:
function ParentComponent() {
const handleData = (childData) => {
console.log("Data from child:", childData);
};
return <ChildComponent sendData={handleData} />;
}
function ChildComponent({ sendData }) {
const data = "Hello from Child";
return <button onClick={() => sendData(data)}>Send Data</button>;
}
-
Батьківський компонент передає функцію
handleData
в пропсsendData
. -
Дочірній компонент викликає
sendData
, передаючи значенняdata
.
- Контекст (Context API):
-
Для передачі даних глибоко по ієрархії без пропсів.
-
Підходить для глобального стану, наприклад, теми чи мови інтерфейсу.
const MyContext = React.createContext();
function ParentComponent() {
const data = "Hello from Context";
return (
<MyContext.Provider value={data}>
<ChildComponent />
</MyContext.Provider>
);
}
function ChildComponent() {
const contextData = React.useContext(MyContext);
return <p>{contextData}</p>;
}
- Менеджери стану (Redux, Zustand, MobX):
- Для передачі даних у великих додатках через єдиний глобальний стан.
- Custom Hooks:
- Використовується для спільного використання логіки між компонентами.
29. Що таке контрольовані компоненти (Controlled Components)?
-
Контрольовані компоненти — це компоненти, в яких React контролює стан форми через
state
. Значення полів форми (наприклад,<input>
,<textarea>
,<select>
) прив'язуються до стану компонента, і зміни обробляються через події. -
Як це працює:
-
Компонент зберігає значення форми у своєму
state
. -
Зміни значення полів форми обробляються через подію
onChange
. -
Значення форми оновлюється, використовуючи
setState
.
- Приклад:
import React, { useState } from "react";
function ControlledForm() {
const [inputValue, setInputValue] = useState("");
const handleChange = (event) => {
setInputValue(event.target.value); // Оновлюємо стан
};
const handleSubmit = (event) => {
event.preventDefault();
console.log("Submitted value:", inputValue);
};
return (
<form onSubmit={handleSubmit}>
<label>
Enter text:
<input
type="text"
value={inputValue} // Значення контролюється state
onChange={handleChange} // Обробка змін
/>
</label>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledForm;
-
Одне джерело істини: Значення форми синхронізоване зі станом компонента.
-
Гнучкість: Легко валідовувати та модифікувати дані форми.
-
Прозорість: Стан форми зрозумілий та передбачуваний.
-
У контрольованих компонентах значення форми контролюється React через
state
. -
У неконтрольованих компонентах значення зберігається в самому DOM, і доступ до нього здійснюється через
ref
. -
Неконтрольований приклад для порівняння:
function UncontrolledForm() {
const inputRef = React.useRef();
const handleSubmit = (event) => {
event.preventDefault();
console.log("Submitted value:", inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<label>
Enter text:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
- Контрольовані компоненти надають кращий контроль та передбачуваність у роботі з формами.
30. Які підходи використовуються для виконання HTTP-запитів у React?
- React не має вбудованого API для виконання HTTP-запитів, але ви можете використовувати сторонні бібліотеки або стандартні засоби JavaScript. Ось основні підходи:
- Використання Fetch API
-
Стандартний інструмент для виконання HTTP-запитів у JavaScript.
-
Приклад:
import React, { useEffect, useState } from "react";
function FetchExample() {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => setData(data))
.catch((error) => setError(error.message));
}, []);
return (
<div>
{error ? (
<p>Error: {error}</p>
) : (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)}
</div>
);
}
export default FetchExample;
- Використання Axios
-
Бібліотека для виконання HTTP-запитів з простішим синтаксисом та вбудованою підтримкою проміжних обробників (interceptors).
-
Приклад:
import React, { useEffect, useState } from "react";
import axios from "axios";
function AxiosExample() {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then((response) => setData(response.data))
.catch((error) => setError(error.message));
}, []);
return (
<div>
{error ? (
<p>Error: {error}</p>
) : (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)}
</div>
);
}
export default AxiosExample;
- React Query (TanStack Query)
-
Бібліотека для управління станом даних, отриманих через HTTP-запити. Підтримує кешування, повторні спроби та оновлення даних.
-
Приклад:
import React from "react";
import { useQuery } from "react-query";
import axios from "axios";
function ReactQueryExample() {
const { data, error, isLoading } = useQuery("posts", async () => {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
return response.data;
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export default ReactQueryExample;
- GraphQL (Apollo Client)
-
Для роботи з GraphQL API використовується Apollo Client.
-
Приклад:
import React from "react";
import { useQuery, gql } from "@apollo/client";
const GET_POSTS = gql`
query GetPosts {
posts {
id
title
}
}
`;
function ApolloExample() {
const { loading, error, data } = useQuery(GET_POSTS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export default ApolloExample;
- Custom Hooks
-
Ви можете створювати власні хуки для повторного використання логіки запитів.
-
Приклад:
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch((error) => {
setError(error.message);
setLoading(false);
});
}, [url]);
return { data, error, loading };
}
export default useFetch;
-
Fetch API: для простих запитів.
-
Axios: якщо потрібна більша гнучкість (interceptors, тайм-аути).
-
React Query: для управління кешем даних.
-
GraphQL/Apollo Client: якщо API побудоване на GraphQL.
-
Custom Hooks: для повторного використання логіки запитів.
31. Що таке неконтрольовані компоненти (Uncontrolled Components)?
- Неконтрольовані компоненти (Uncontrolled Components) — це компоненти, які зберігають свій стан у DOM, а не у внутрішньому стані React-компонента. Доступ до значень таких компонентів здійснюється за допомогою рефів (refs).
-
Стан керується DOM: значення полів зберігаються та оновлюються безпосередньо у DOM.
-
Менше інтеграції з React: вони не використовують useState або будь-які інші засоби React для зберігання стану.
-
Застосування рефів: для отримання доступу до значення полів форми використовується ref.
import React, { useRef } from "react";
function UncontrolledForm() {
const inputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
alert(`Введене значення: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Ім'я:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Відправити</button>
</form>
);
}
export default UncontrolledForm;
-
Якщо потрібна мінімальна інтеграція React із DOM.
-
Якщо значення форми обробляються сторонніми бібліотеками.
-
Якщо необхідна проста форма без складної логіки.
-
Простота реалізації для простих форм.
-
Менше коду для управління станом.
-
Менший контроль над значеннями.
-
Складніше реалізувати валідацію або синхронізацію даних.
-
Менш React-орієнтований підхід.
32. Способи стилізації в React-компонентах?
- Inline-стилі Стилі передаються безпосередньо у вигляді об’єкта через атрибут
style
.
function InlineStyle() {
const style = {
color: "blue",
fontSize: "20px",
};
return <h1 style={style}>Привіт, React!</h1>;
}
- CSS-файли Використання звичайних CSS-файлів, які імпортуються в компонент.
import "./styles.css";
function CSSFile() {
return <h1 className="heading">Привіт, React!</h1>;
}
Копіювати
Редагувати
/* styles.css */
.heading {
color: blue;
font-size: 20px;
}
- CSS-модулі Створюють локально ізольовані стилі для кожного компонента.
import styles from "./styles.module.css";
function CSSModule() {
return <h1 className={styles.heading}>Привіт, React!</h1>;
}
/* styles.module.css */
.heading {
color: blue;
font-size: 20px;
}
- Styled Components Використання бібліотеки styled-components для написання стилів у JavaScript.
npm install styled-components
import styled from "styled-components";
const Heading = styled.h1`
color: blue;
font-size: 20px;
`;
function StyledComponent() {
return <Heading>Привіт, React!</Heading>;
}
- Emotion Альтернативна бібліотека для стилізації, схожа на styled-components.
npm install @emotion/react @emotion/styled
/**_ @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
const style = css`
color: blue;
font-size: 20px;
`;
function EmotionStyle() {
return <h1 css={style}>Привіт, React!</h1>;
}
- CSS-in-JS Створення динамічних стилів у звичайних JavaScript-файлах.
function CSSInJS({ isBlue }) {
const style = {
color: isBlue ? "blue" : "red",
fontSize: "20px",
};
return <h1 style={style}>Привіт, React!</h1>;
}
- Tailwind CSS Фреймворк класів утиліт для стилізації компонентів.
function TailwindExample() {
return <h1 className="text-blue-500 text-2xl">Привіт, React!</h1>;
}
- Налаштування Tailwind CSS: додайте залежності та налаштуйте конфігурацію.
- Sass/SCSS Розширений CSS із підтримкою змінних, міксинів та вкладеності.
npm install sass
import "./styles.scss";
function SCSSExample() {
return <h1 className="heading">Привіт, React!</h1>;
}
/* styles.scss */
.heading {
color: blue;
font-size: 20px;
}
-
Масштабності проекту.
-
Потреби в ізоляції стилів.
-
Переваг команди.
33. Яка різниця між createElement і cloneElement?
Метод | Опис | Основне застосування |
---|---|---|
React.createElement |
Створює новий елемент React. Приймає тип елемента, пропси та дочірні елементи як аргументи. | Використовується для створення елементів React з нуля, зазвичай під час рендерингу JSX. |
React.cloneElement |
Клонує існуючий елемент React, дозволяючи змінити його пропси або дочірні елементи. | Використовується для створення змінених копій вже існуючих елементів React. |
React.createElement
const element = React.createElement(
"div",
{ className: "example" },
"Привіт, React!"
);
Результат: створюється <div class="example">Привіт, React!</div>
.
React.cloneElement
const originalElement = <button className="primary">Натисни</button>;
const clonedElement = React.cloneElement(originalElement, {
className: "secondary",
});
Результат: клон <button class="secondary">Натисни</button>
зі зміненим класом.
-
createElement
: створює абсолютно новий елемент. -
cloneElement
: працює на основі вже існуючого елемента, дозволяючи змінювати його властивості або вміст.
34. Що таке компоненти вищого порядку (Higher-Order components)?
- Компонент вищого порядку — це функція, яка приймає компонент як вхідний аргумент і повертає новий компонент, розширюючи його функціональність.
const EnhancedComponent = higherOrderComponent(WrappedComponent);
-
Приймає компонент як аргумент.
-
Повертає новий компонент із додатковими властивостями чи поведінкою.
-
Дозволяє перевикористовувати логіку у різних компонентах.
- HOC для додавання стану до компонента:
import React, { useState } from "react";
// HOC: додає логіку роботи зі станом
function withCounter(WrappedComponent) {
return function EnhancedComponent(props) {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return <WrappedComponent count={count} increment={increment} {...props} />;
};
}
// Компонент, який буде розширено
function Button({ count, increment }) {
return <button onClick={increment}>Clicked {count} times</button>;
}
// Використання HOC
const EnhancedButton = withCounter(Button);
export default EnhancedButton;
-
Авторизація (Authentication) — обгортання компонентів для перевірки прав доступу.
-
Обробка даних — підключення до API чи обробка стану.
-
Логування — додавання журналювання дій компонентів.
-
Може створювати глибокі вкладення (component tree), якщо використовувати забагато HOC.
-
Ускладнює читабельність через обгортання компонентів.
HOC — потужний інструмент для повторного використання логіки, але в сучасних додатках їх часто замінюють React Hooks.
35. Що таке Lifting State Up у React?
Lifting State Up — це підхід у React, коли стан (state) піднімається до найближчого спільного предка компонентів, яким потрібно спільно використовувати цей стан. Це дозволяє організувати єдине джерело правди для управління даними між компонентами.
-
Компоненти, які мають спільно використовувати дані, не повинні кожен мати власний стан.
-
Стан піднімається до батьківського компонента, який передає дані через props дочірнім компонентам.
-
Батьківський компонент зберігає стан.
-
Він передає стан та функції для оновлення стану своїм дочірнім компонентам через props.
-
Дочірні компоненти повідомляють батька про зміни, використовуючи передані функції.
import React, { useState } from "react";
function TemperatureInput({ temperature, onTemperatureChange }) {
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
type="number"
value={temperature}
onChange={(e) => onTemperatureChange(e.target.value)}
/>
</fieldset>
);
}
function BoilingVerdict({ celsius }) {
return celsius >= 100 ? (
<p>The water will boil.</p>
) : (
<p>The water won't boil.</p>
);
}
function Calculator() {
const [temperature, setTemperature] = useState("");
return (
<div>
<TemperatureInput
temperature={temperature}
onTemperatureChange={setTemperature}
/>
<BoilingVerdict celsius={parseFloat(temperature)} />
</div>
);
}
export default Calculator;
-
Забезпечує єдине джерело правди для стану.
-
Полегшує синхронізацію даних між компонентами.
-
Робить компоненти більш передбачуваними та повторно використовуваними.
36. Як створити форму в React?
- Форми в React створюються за допомогою елементів
<form>
та відповідних контролів, як-от<input>
,<textarea>
,<select>
. Реактивність форм забезпечується керованими або некерованими компонентами.
- Керовані компоненти використовують стан (state) для відстеження значення полів форми.
import React, { useState } from "react";
function ControlledForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
console.log("Submitted:", { name, email });
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<br />
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
export default ControlledForm;
-
Особливості:
-
Кожне поле контролюється через
state
. -
Легко синхронізувати та обробляти дані форми.
-
- Некеровані компоненти використовують реф (
ref
) для прямого доступу до DOM-елементів.
import React, { useRef } from "react";
function UncontrolledForm() {
const nameRef = useRef();
const emailRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
console.log("Submitted:", {
name: nameRef.current.value,
email: emailRef.current.value,
});
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={nameRef} />
</label>
<br />
<label>
Email:
<input type="email" ref={emailRef} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
export default UncontrolledForm;
-
Особливості:
-
Доступ до значень здійснюється через ref.
-
Підходить для простих форм.
-
- Керована форма:
-
Використовує
state
. -
Більш підходить для складних форм, що потребують валідації або синхронізації.
- Некерована форма:
-
Використовує
ref
. -
Простий підхід без складної логіки управління станом.
Вибір підходу залежить від складності форми та потреб у взаємодії з її полями.
37. Що таке children prop?
children
— це спеціальний пропс у React, який використовується для передачі вкладених елементів або компонентів у компонент-обгортку.
- Коли ви передаєте дочірній вміст між відкриваючим і закриваючим тегами компонента, цей вміст автоматично передається як значення
props.children
.
- Компонент-обгортка:
function Wrapper({ children }) {
return <div className="wrapper">{children}</div>;
}
- Використання:
function App() {
return (
<Wrapper>
<h1>Hello, World!</h1>
<p>This is a paragraph inside the wrapper.</p>
</Wrapper>
);
}
- Результат:
<div class="wrapper">
<h1>Hello, World!</h1>
<p>This is a paragraph inside the wrapper.</p>
</div>
-
Гнучкість: Можна передавати будь-який тип даних: текст, JSX, компоненти, масиви елементів.
-
Повторне використання: Компонент-обгортка може динамічно відображати різний вміст.
-
Структурованість: Допомагає створювати компоненти з вкладеною структурою.
Іноді children
використовується як функція для динамічної передачі даних:
function List({ items, children }) {
return <ul>{items.map((item) => children(item))}</ul>;
}
function App() {
return (
<List items={["Apple", "Banana", "Cherry"]}>
{(item) => <li key={item}>{item}</li>}
</List>
);
}
- Результат:
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
children
— це потужний інструмент для створення універсальних і багаторазових компонентів у React.
38. Як реалізувати додавання класу за умовою в React?
- В React умовне додавання класів до елементів зазвичай здійснюється через атрибут
className
і використання тернарного оператора або функцій для визначення умов.
- Тернарний оператор
function MyComponent({ isActive }) {
return (
<div className={isActive ? "active-class" : "inactive-class"}>Hello</div>
);
}
- Якщо
isActive
дорівнюєtrue
, до елемента буде додано класactive-class
. - Інакше —
inactive-class
.
- Шаблонні рядки
function MyComponent({ isHighlighted }) {
return (
<div className={`base-class ${isHighlighted ? "highlighted-class" : ""}`}>
Hello
</div>
);
}
- Завжди додається
base-class
. - Якщо
isHighlighted
дорівнює true, додається ще йhighlighted-class
.
- Бібліотека
clsx
clsx
допомагає працювати з класами більш елегантно.
npm install clsx
import clsx from "clsx";
function MyComponent({ isActive, isDisabled }) {
return (
<div
className={clsx("base-class", {
"active-class": isActive,
"disabled-class": isDisabled,
})}
>
Hello
</div>
);
}
clsx
дозволяє легко додавати кілька класів на основі умов.
- Бібліотека
classnames
- Схожа на
clsx
, але має більше можливостей.
npm install classnames
import classNames from "classnames";
function MyComponent({ isActive, isDisabled }) {
return (
<div
className={classNames("base-class", {
"active-class": isActive,
"disabled-class": isDisabled,
})}
>
Hello
</div>
);
}
- Винесення логіки в окрему функцію
function getClassName(isActive, isDisabled) {
let className = "base-class";
if (isActive) className += " active-class";
if (isDisabled) className += " disabled-class";
return className;
}
function MyComponent({ isActive, isDisabled }) {
return <div className={getClassName(isActive, isDisabled)}>Hello</div>;
}
- Логіка визначення класів стає більш читабельною та може бути перевикористана.
-
Для простих випадків підійде використання тернарного оператора або шаблонних рядків.
-
Для складних умов краще застосовувати бібліотеки
clsx
абоclassnames
, які забезпечують зручність і читаємість коду.
39. Як писати коментарі в React?
- В React коментарі пишуться так само, як і в JavaScript, але є певні нюанси, коли мова йде про JSX.
- Коментарі в JavaScript (за межами JSX)
// Однорядковий коментар
/*
Багаторядковий коментар
*/
- Коментарі всередині JSX
-
У JSX необхідно використовувати спеціальний синтаксис, оскільки JSX є частиною JavaScript.
-
Коментарі в JSX потрібно писати всередині фігурних дужок
{}
:
function MyComponent() {
return (
<div>
{/_ Це коментар всередині JSX _/}
<h1>Hello, world!</h1>
</div>
);
}
-
Коментарі в JSX повинні бути оточені
{/* коментар */}
, інакше вони викликають помилки. -
Вони можуть бути використані тільки всередині виразів JSX.
- Коментарі в функціях та методах
- Для коментарів всередині функцій або методів можна використовувати стандартні JavaScript коментарі:
function MyComponent() {
// Ось тут ми рендеримо компонент
return <div>Hello, world!</div>;
}
-
У JSX використовуйте
{/* коментар */}
. -
У звичайному JavaScript —
//
для однорядкових і/* ... */
для багаторядкових коментарів.
40. Що таке фрагменти (Fragments) у React?
- Фрагменти в React — це спосіб групувати кілька елементів без додавання зайвих елементів в DOM. Вони дозволяють повернути декілька елементів з компонента без обгортки, такої як
div
, що може допомогти уникнути зайвих елементів, що можуть порушити стилі або структуру документа.
- Без фрагментів (з обгорткою):
function MyComponent() {
return (
<div>
<h1>Title</h1>
<p>Some text</p>
</div>
);
}
- У цьому прикладі повертається один
div
, який обгортаєh1
іp
.
- З фрагментами (без обгортки):
function MyComponent() {
return (
<>
<h1>Title</h1>
<p>Some text</p>
</>
);
}
Тепер h1
і p
рендеряться без додаткового контейнера, що дозволяє зберегти чистоту DOM.
-
Чистий DOM: Можна обходитись без зайвих обгорток у DOM.
-
Зручність для рендерингу кількох елементів: Повернення кількох елементів з одного компонента без необхідності використовувати додаткові елементи.
-
Можна використовувати порожні теги
<>
і</>
, які є скороченням для<React.Fragment></React.Fragment>
. -
Також можна використовувати
React.Fragment
, якщо потрібно додавати ключі (наприклад, при рендерингу списків):
<React.Fragment key={item.id}>
<h1>{item.name}</h1>
<p>{item.description}</p>
</React.Fragment>
-
Коли потрібно рендерити кілька елементів без додаткової обгортки в DOM.
-
Коли зберігаєте структуру компонента без порушення стилів чи верстки.
Фрагменти є дуже корисними для зменшення зайвих елементів у DOM та покращення продуктивності.
41. Що таке узгодження (Reconciliation)?
- Reconciliation (узгодження) — це процес, який React використовує для оновлення DOM найефективнішим способом. Коли стан або пропси компонента змінюються, React обчислює мінімальні зміни, які потрібно внести до реального DOM, щоб синхронізувати його зі станом віртуального DOM.
- Порівняння старого та нового віртуального DOM:
- React зберігає копію попереднього віртуального DOM.
- При зміні стану чи пропсів створюється новий віртуальний DOM.
- React порівнює новий віртуальний DOM із попередньою копією (алгоритм diffing).
- Виявлення відмінностей (diffing):
- React ідентифікує, які частини дерева змінилися (нові елементи, зміни в атрибутах чи видалення елементів).
- Для цього використовується алгоритм, оптимізований для роботи з деревоподібними структурами.
- Оновлення реального DOM:
- React застосовує зміни лише до тих частин DOM, які потрібно оновити, уникаючи повного перерендеру.
- Збереження вузлів одного рівня: Якщо вузли мають однаковий тип (наприклад,
<div>
залишається<div>
), React змінює лише атрибути та дочірні елементи. - Повторне використання компонентів: Якщо компонент залишається тим самим, React повторно використовує існуючий екземпляр компонента.
- Ключі для списків: Якщо список елементів рендериться з масиву, React використовує ключі (
key
prop) для порівняння та збереження вузлів.
function App({ isVisible }) {
return isVisible ? <h1>Hello</h1> : <p>Goodbye</p>;
}
- Якщо
isVisible
змінюється зtrue
наfalse
, React видалить<h1>
і замінить його на<p>
.
- Ключі допомагають React коректно визначати зміни в списках. Наприклад:
<ul>
{items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
- Без унікальних ключів React не зможе точно визначити, які елементи списку змінилися.
- Зменшення кількості операцій із DOM.
- Підвищення продуктивності додатків.
- Гладке оновлення інтерфейсу користувача.
42. Чи підтримує функція lazy іменований експорт?
- Ні, функція
React.lazy
не підтримує іменований експорт. Вона працює лише з експортом за замовчуванням. Якщо у вас є модуль з іменованим експортом, і ви хочете використовувати його зReact.lazy
, потрібно створити обгортку, яка експортує потрібний компонент за замовчуванням.
// Іменований експорт
export const MyComponent = () => {
return <div>Hello, World!</div>;
};
// Використання React.lazy
const LazyComponent = React.lazy(() =>
import("./MyComponent").then((module) => ({ default: module.MyComponent }))
);
export default LazyComponent;
- Тут ми явно вказуємо, що module.MyComponent має бути використаний як експорт за замовчуванням.
43. Які підходи ви знаєте для оптимізації продуктивності React-додатків?
- Мемоїзація компонентів:
- Використовуйте
React.memo
для мемоїзації функціональних компонентів, які не залежать від частих оновлень пропсів. - Використовуйте
PureComponent
для класових компонентів.
- Мемоїзація значень та функцій:
useMemo
— для обчислення значень, які залежать від певних залежностей.useCallback
— для мемоїзації функцій, які передаються в дочірні компоненти.
- Оптимізація рендерингу списків:
Завжди використовуйте унікальний key для елементів у списках. Уникайте повторного рендерингу компонентів без потреби.
- Динамічне завантаження компонентів:
- Використовуйте
React.lazy
для завантаження компонентів на вимогу. - В поєднанні з
Suspense
це дозволяє оптимізувати завантаження додатку.
- Контроль за ререндерингом:
- Використовуйте
shouldComponentUpdate
абоReact.memo
для зменшення непотрібних рендерів. - Використовуйте
React.Fragment
замість додаткових обгорткових елементів.
- Розділення коду (Code Splitting):
- Впроваджуйте
React.lazy
та динамічні імпорти, щоб завантажувати код модулів лише тоді, коли це потрібно.
- Управління станом:
- Уникайте зберігання глобального стану для компонентів, де це не потрібно.
- Виносьте важкі операції зі станом у контекст або спеціалізовані бібліотеки (Redux, Zustand).
- Віртуалізація списків:
- Використовуйте бібліотеки, такі як
react-window
абоreact-virtualized
, для рендерингу лише видимих елементів списків.
- Оптимізація зображень:
- Використовуйте відкладене завантаження (
lazy loading
) для зображень. - Стискайте та оптимізуйте зображення перед використанням.
- Зменшення кількості компонентів в DOM:
- Уникайте надмірного вкладення компонентів.
- Видаляйте непотрібні елементи з DOM при переходах між сторінками.
- Кешування даних:
- Використовуйте кешуючі бібліотеки, такі як
SWR
чиReact Query
, для управління даними та зменшення запитів до сервера.
- Використання Production-збірки:
- Упевніться, що додаток побудований за допомогою production-режиму (
npm run build
). - Використовуйте інструменти, такі як
Webpack
, для мінімізації та оптимізації коду.
- Профілювання додатку:
- Використовуйте
React DevTools
для аналізу продуктивності. - Виявляйте "вузькі місця" за допомогою вкладки "Profiler".
- Оптимізація CSS та стилів:
- Використовуйте
CSS-in-JS
рішення (наприклад,styled-components
) тільки там, де це необхідно. - Стискайте стилі за допомогою
PostCSS
або інших інструментів.
Ці підходи допомагають зменшити затримки, підвищити швидкість рендерингу та загальну продуктивність додатку.
44. Чому React використовує className замість атрибута класу?
- У React використовується
className
замістьclass
, тому щоclass
є зарезервованим ключовим словом у JavaScript.
-
Уникнення конфліктів –
class
використовується для визначення класів у JavaScript (class MyComponent {}
), що могло б викликати синтаксичні помилки. -
Сумісність з JSX – JSX є синтаксичним розширенням JavaScript, тому використання
className
допомагає уникнути неоднозначностей. -
Пряме відображення у
document.createElement
– React перетворює JSX у викликиReact.createElement
, і для встановлення класів у DOM-елементах використовуєтьсяclassName
.
// Коректний варіант у React
<div className="my-class">Hello</div>
// Некоректний варіант (синтаксична помилка)
<div class="my-class">Hello</div>
- Це стандарт React, який гарантує стабільність і узгодженість у коді.
45. Чому фрагменти (Fragment) кращі за контейнерні div?
- Фрагменти (
<React.Fragment>
або<>...</>
) кращі за контейнерні<div>
у React з кількох причин:
- Зменшення зайвого HTML
- Фрагменти не додають додатковий елемент у DOM, що зменшує кількість вкладених тегів і покращує продуктивність.
<>
<h1>Title</h1>
<p>Text</p>
</>
- Результат у DOM:
<h1>Title</h1>
<p>Text</p>
- На відміну від
<div>
, який би додавав зайву вкладеність:
<div>
<h1>Title</h1>
<p>Text</p>
</div>
- Відсутність стилістичних побічних ефектів
- Додатковий
<div>
може впливати на CSS-стилі, спричиняючи небажані зміни у верстці. Фрагменти цього уникають.
- Краща сумісність з таблицями
- У
<table>
не можна безпосередньо вкладати<div>
, але можна використовувати фрагменти:
<>
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
</>
- Це працює правильно, тоді як
<div>
спричинив би помилку.
- Оптимізація продуктивності
- Менше зайвих вузлів у DOM → швидший рендеринг та менше споживання пам’яті.
46. Що таке компоненти без стану (stateless components)?
- Компоненти без стану (stateless components) — це компоненти, які не зберігають і не обробляють жодного внутрішнього стану. Вони лише отримують дані через props і відображають їх у вигляді UI. Зазвичай ці компоненти є функціональними.
-
Відсутність стану: Вони не використовують this.state і не змінюють свій внутрішній стан.
-
Тільки рендеринг: Вони просто отримують пропси та відображають їх у вигляді елементів UI.
-
Простота та передбачуваність: Легше тестувати і підтримувати, оскільки не потрібно слідкувати за змінами стану.
// Stateless component
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Використання:
<Greeting name="John" />;
-
Простота: Легше розуміти та підтримувати.
-
Оптимізація продуктивності: Оскільки ці компоненти не мають стану, React може більш ефективно їх оновлювати.
- Коли компонент просто відображає дані та не потребує змін.
47. Що таке компоненти стану (stateful components)?
- Компоненти стану (stateful components) — це компоненти, які зберігають і управляють своїм внутрішнім станом. Вони використовують state для збереження даних, які можуть змінюватися протягом часу, і ці зміни впливають на рендеринг компонента.
-
Стан (state): Вони використовують this.state для зберігання і управління даними, які можуть змінюватися.
-
Методи для оновлення стану: Використовують метод this.setState() для оновлення стану.
-
Життєвий цикл: Мають доступ до методів життєвого циклу компонента, таких як componentDidMount(), shouldComponentUpdate(), componentDidUpdate() тощо.
// Stateful component
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
-
Динамічні компоненти: Можуть змінювати свій вміст і вигляд на основі змін в стані.
-
Інтерактивність: Підходять для створення інтерактивних інтерфейсів, де є потреба в оновленні стану при взаємодії з користувачем.
- Коли компонент потребує управління внутрішнім станом, наприклад, для збереження введених даних у формі, рахунку, вибору тощо.
48. Як застосувати перевірку пропсів (props) у React?
- Для перевірки пропсів у React використовують PropTypes.
- Встановлення PropTypes (якщо не встановлено)
npm install prop-types
- Використання PropTypes у функціональному компоненті:
import React from "react";
import PropTypes from "prop-types";
function UserCard({ name, age, isAdmin }) {
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
{isAdmin && <p>Admin Access</p>}
</div>
);
}
// Визначення PropTypes
UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
isAdmin: PropTypes.bool,
};
// Значення за замовчуванням
UserCard.defaultProps = {
age: 18,
isAdmin: false,
};
export default UserCard;
- Використання у класовому компоненті:
import React from "react";
import PropTypes from "prop-types";
class UserCard extends React.Component {
render() {
const { name, age, isAdmin } = this.props;
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
{isAdmin && <p>Admin Access</p>}
</div>
);
}
}
// Визначення PropTypes
UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
isAdmin: PropTypes.bool,
};
// Значення за замовчуванням
UserCard.defaultProps = {
age: 18,
isAdmin: false,
};
export default UserCard;
PropTypes.string
PropTypes.number
PropTypes.bool
PropTypes.array
PropTypes.object
PropTypes.func
PropTypes.node
(JSX або текст)PropTypes.element
(React-елемент)PropTypes.oneOf(['value1', 'value2'])
(перелік допустимих значень)PropTypes.shape({ key: PropTypes.type })
(об'єкт із певною структурою)
PropTypes допомагають уникнути помилок, перевіряючи типи пропсів, але в TypeScript це робиться на рівні самої мови.
49. React DevTools: Як використовувати для налагодження?
- Встановлення React DevTools
-
Якщо використовуєш
Chrome
абоFirefox
, просто встанови розширенняReact Developer Tools
:- Chrome Web Store
- Firefox Add-ons
-
Якщо налагоджуєш
Electron
,React Native
або інший нестандартний оточення, встанови:
npm install -g react-devtools
react-devtools
- Основні вкладки та їх використання
- ⚛ Components → перегляд структури компонентів, стану та пропсів.
- ⚡ Profiler → аналіз продуктивності та виявлення зайвих рендерів.
- Дебаг пропсів і стану
- Відкрий вкладку Components.
- Вибери компонент → побачиш його
props
,state
,context
. - Можеш редагувати
state
іprops
прямо уDevTools
, щоб тестувати зміну поведінки.
- Виявлення зайвих рендерів
- У вкладці Profiler натисни "Record", зроби взаємодію, натисни "Stop".
- Перевір кольорове маркування:
- Червоний → дорогий рендер.
- Жовтий → середня вартість.
- Синій → легкий рендер.
- Оптимізуй компоненти через
React.memo()
,useMemo()
,useCallback()
.
- Інструменти для відладки Context API
- Якщо використовуєш React Context, можна перевірити його значення в DevTools.
- Вибери компонент, який використовує
useContext()
, і знайди вкладку Context.
- Відладка рендеру в Strict Mode
- Якщо
React DevTools
показує, що компонент рендериться двічі, перевір StrictMode уindex.js
:
<React.StrictMode>
<App />
</React.StrictMode>
- Він не викликає багів, а лише допомагає виявити потенційні проблеми.
- Інспекція хуків
- DevTools дозволяє бачити стан хуків (
useState
,useEffect
,useReducer
). - У вкладці Components вибери компонент → побачиш стан
useState
.
- React DevTools — це потужний інструмент для налагодження стану, пропсів, продуктивності та контексту. Використовуй Profiler для оптимізації та Components для відстеження змін у стані та пропсах.
50. Які переваги React?
- Висока продуктивність
- Використання Virtual DOM мінімізує оновлення реального DOM, що робить рендеринг швидшим.
- Компонентний підхід
- Додаток складається з повторно використовуваних компонентів, що спрощує розробку та підтримку.
- Одностороння передача даних (Unidirectional Data Flow)
- Дані передаються вниз по ієрархії компонентів, що спрощує відстеження змін стану.
- Підтримка хуків (Hooks)
useState
,useEffect
,useMemo
тощо дозволяють керувати станом та ефектами у функціональних компонентах без класів.
- Серверний рендеринг (SSR) та статична генерація (SSG)
- З Next.js можна оптимізувати SEO та покращити продуктивність додатків.
- Гнучкість та екосистема
-
React можна використовувати разом із Redux, Zustand, MobX, React Query, тощо.
-
Підтримує React Native для створення мобільних додатків.
- Розширені можливості налагодження
- React DevTools дозволяє переглядати структуру компонентів, стан та пропси в реальному часі.
- Активна спільнота та підтримка Facebook
- Великий вибір бібліотек та готових рішень, швидкий розвиток фреймворку.
React — це гнучкий, продуктивний і сучасний інструмент для розробки веб-додатків.
51. Які обмеження React?
-
Велика кількість перерендерів: Якщо компоненти неправильно оптимізовані, це може призвести до надмірних перерендерів, що погіршує продуктивність.
-
Необхідність керувати станом: Без правильного управління станом додаток може стати складним для підтримки.
-
Однонаправлений потік даних: Потік даних йде лише в одному напрямку, що може ускладнювати передачу даних через кілька рівнів компонентів.
-
Реактивність: React оновлює DOM через віртуальний DOM, але це може бути неефективно для великих, динамічних додатків.
-
Залежність від JavaScript: Погана підтримка без JavaScript на клієнтській стороні.
-
Навчання для новачків: Хоча концепції React досить прості, правильно освоїти хуки, контексти та оптимізацію може бути важко.
-
Інструменти сторонніх розробників: Хоча існує велика кількість інструментів, їх інтеграція може бути складною в великих проектах.
52. Як рефи (refs) у React використовуються для взаємодії з DOM елементами?
- Рефи (refs) у React використовуються для отримання доступу до DOM елементів або компонентів безпосередньо, обминаючи стандартний механізм пропсів та стану.
- Створення рефів: Використовуєш
React.createRef()
для створення рефа.
const myRef = React.createRef();
- Прив'язка рефа до елемента: Реф передається до DOM елемента через атрибут
ref
.
<input ref={myRef} />
- Взаємодія з DOM: Реф дає доступ до DOM елемента через
.current
. Наприклад, щоб встановити фокус:
myRef.current.focus();
-
Обмеження: Рефи не повинні використовуватися для керування станом, вони призначені лише для взаємодії з DOM, коли це необхідно (наприклад, для фокусу, вибору тексту чи анімацій).
-
Функціональні компоненти: В React 16.8 і вище для функціональних компонентів використовують useRef.
const inputRef = useRef();
inputRef.current.focus();
53. Які рекомендовані способи перевірки статичних типів?
-
TypeScript: Найбільш популярний та повний підхід для статичної типізації в JavaScript/React. TypeScript додає строгі типи до вашого коду, дозволяючи перевіряти типи на етапі компіляції.
-
PropTypes: Вбудований механізм для перевірки типів пропсів у React компонентах. Використовується для валідації типів під час виконання. Це не дає статичної типізації на етапі компіляції, але дозволяє перевіряти пропси під час виконання додатка.
MyComponent.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
};
-
Flow: Інший механізм для статичної типізації в JavaScript. Flow є менш популярним, ніж TypeScript, але також дозволяє додавати типи та перевіряти їх на етапі компіляції.
-
ESLint з плагінами для типізації: Можна використовувати ESLint з плагінами для перевірки типів (наприклад, eslint-plugin-flowtype або eslint-plugin-typescript), але це не дає такої глибини типізації, як TypeScript.
- Рекомендую використовувати TypeScript, оскільки він інтегрується з React та іншими інструментами і надає повну статичну типізацію на етапі компіляції.
54. Як реалізувати анімацію в React?
- CSS анімації: Найпростіший спосіб — використання стандартних CSS анімацій або переходів.
<div className="my-element">Hello</div>
<style jsx>{`
.my-element {
animation: fadeIn 1s ease-in-out;
}
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
`}</style>
- React Transition Group: Для більш складних анімаційних переходів між компонентами. Цей пакет дозволяє керувати анімацією під час додавання чи видалення компонентів.
import { CSSTransition } from 'react-transition-group';
<CSSTransition in={isVisible} timeout={300} classNames="fade" unmountOnExit>
<div>Content</div>
</CSSTransition>
<style jsx>{`
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms;
}
.fade-exit {
opacity: 1;
}
.fade-exit-active {
opacity: 0;
transition: opacity 300ms;
}
`}</style>
- Framer Motion: Це потужна бібліотека для анімацій, яка дозволяє реалізувати складні анімації в React.
import { motion } from "framer-motion";
<motion.div
animate={{ opacity: 1 }}
initial={{ opacity: 0 }}
transition={{ duration: 1 }}
>
Hello
</motion.div>;
- React Spring: Для фізично базованих анімацій, що дозволяють створювати анімації з реалістичними рухами.
import { useSpring, animated } from "react-spring";
const props = useSpring({ opacity: 1, from: { opacity: 0 } });
<animated.div style={props}>Hello</animated.div>;
- Inline стилі та JavaScript: Можна використовувати setState та змінювати стилі на основі стану компонента.
const [opacity, setOpacity] = useState(0);
useEffect(() => {
setOpacity(1);
}, []);
return <div style={{ opacity }}>Hello</div>;
- Для складніших анімаційних ефектів рекомендується використовувати Framer Motion або React Spring, бо ці бібліотеки дають більше можливостей та легше керувати складними анімаціями.
55. Яке використання пакету react-dom?
- Пакет
react-dom
використовується для взаємодії React з реальним DOM у веб-додатках. Основні функції:
ReactDOM.render()
: Використовується для рендерингу компонента в реальний DOM. Це основний метод, який зв'язує React з HTML-елементами.
ReactDOM.render(<App />, document.getElementById("root"));
ReactDOM.hydrate()
: Використовується для гідратації серверно-рендереного HTML (наприклад, для SSR). Це дозволяє React взяти на себе управління вже наявним HTML.
ReactDOM.hydrate(<App />, document.getElementById("root"));
ReactDOM.createPortal()
: Дозволяє рендерити дочірні елементи в іншому місці DOM, поза межами звичайної ієрархії компонентів. Це часто використовується для модальних вікон, тултіпів і спливаючих елементів.
ReactDOM.createPortal(<Modal />, document.getElementById("modal-root"));
ReactDOM.unmountComponentAtNode()
: Видаляє React-компонент з DOM.
ReactDOM.unmountComponentAtNode(document.getElementById("root"));
ReactDOM.findDOMNode()
: Дає доступ до реального DOM елемента компонента (рідко використовується, бо є більш сучасні підходи через рефи).
- Цей пакет необхідний для роботи з реальним DOM, але в більшості випадків, після початкової установки, вам не потрібно вручну викликати ці методи, оскільки вони автоматично використовуються за допомогою інструментів для компіляції та рендерингу.
56. Як в React працює механізм контексту (Context) для спільної передачі даних між компонентами?
- Механізм React Context дозволяє передавати дані між компонентами без необхідності передавати їх через пропси на кожному рівні компонентів. Це корисно для глобальних даних, таких як налаштування теми, аутентифікація користувача чи мова.
- Створення контексту: Для створення контексту використовується React.createContext(). Це повертає два компоненти:
-
Provider — компонент, який передає значення контексту.
-
Consumer — компонент, який отримує значення контексту.
const MyContext = React.createContext();
- Надання контексту: Використовуємо Provider, щоб огорнути компоненти, яким потрібно передавати контекст. В Provider передається значення через пропс value.
const App = () => {
const [user, setUser] = useState("John Doe");
return (
<MyContext.Provider value={user}>
<Child />
</MyContext.Provider>
);
};
- Отримання контексту: Використовуємо Consumer або хук useContext для доступу до значення контексту.
- Consumer:
const Child = () => (
<MyContext.Consumer>{(user) => <div>{user}</div>}</MyContext.Consumer>
);
- useContext хук (рекомендовано в функціональних компонентах):
const Child = () => {
const user = useContext(MyContext);
return <div>{user}</div>;
};
- Зміна контексту: Для зміни значення контексту можна використовувати функції, передані через
useState
або інші методи управління станом.
const App = () => {
const [user, setUser] = useState("John Doe");
return (
<MyContext.Provider value={user}>
<button onClick={() => setUser("Jane Doe")}>Change User</button>
<Child />
</MyContext.Provider>
);
};
-
Контекст дозволяє уникати "prop drilling" (передавання пропсів через багато компонентів).
-
Якщо значення контексту змінюється, всі компоненти, які споживають цей контекст, будуть перерендерені.
-
useContext — зручніший і сучасніший спосіб отримати значення контексту в порівнянні з
Consumer
.
Контекст — це потужний інструмент, але використовувати його варто тільки для глобальних даних. Для локального стану краще використовувати звичайний state.
57. Що таке ReactDOMServer?
ReactDOMServer
— це бібліотека, що входить до складу React, і використовується для рендерингу React-компонентів на сервері, тобто для серверного рендерингу (SSR). Це дозволяє генерувати HTML-код на сервері і передавати його на клієнт, що може покращити продуктивність і SEO.
ReactDOMServer.renderToString()
: Рендерить React-елементи в HTML-строку. Це основний метод для генерації статичного HTML для початкового завантаження сторінки.
import ReactDOMServer from "react-dom/server";
const html = ReactDOMServer.renderToString(<App />);
ReactDOMServer.renderToStaticMarkup()
: Рендерить HTML без будь-яких додаткових атрибутів, пов'язаних з React, таких як data-reactroot. Це підходить для створення повністю статичних сторінок.
const html = ReactDOMServer.renderToStaticMarkup(<App />);
ReactDOMServer.hydrate()
: Використовується на клієнтській стороні для "гідратації" серверно-рендереного HTML, тобто для прив'язування реактивності до уже існуючого HTML.
ReactDOM.hydrate(<App />, document.getElementById("root"));
-
SSR (Server-Side Rendering): Це підхід, при якому React-компоненти рендеряться на сервері, а не в браузері, що дозволяє надсилати повністю сформовану HTML-сторінку на клієнт.
-
SEO: Оскільки сервер відразу відправляє HTML-контент, пошукові системи можуть індексувати сторінки без необхідності виконувати JavaScript.
Таким чином, ReactDOMServer
дозволяє створювати попередньо рендерені сторінки, що покращує швидкість завантаження і може бути корисним для SEO.
58. Як обробляти помилки в React за допомогою Error Boundary?
- Error Boundaries у React дозволяють ловити помилки у компонентах під час рендерингу, в методах життєвого циклу та в конструкторах, а також обробляти їх без повного зупинення додатку.
-
Error Boundary — це компонент, який обгортає інші компоненти і може ловити помилки, що виникають в їхньому коді.
-
Error Boundaries ловлять лише помилки, що сталися в їхніх нащадках. Вони не ловлять помилки в самому Error Boundary.
- Створення Error Boundary: Для створення Error Boundary потрібно реалізувати два методи:
-
static getDerivedStateFromError(error)
— оновлює стан при виникненні помилки. -
componentDidCatch(error, info)
— дозволяє реєструвати помилки (наприклад, надсилати їх на сервер).
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
// Оновлюємо стан, щоб показати запасний UI
return { hasError: true, error };
}
componentDidCatch(error, info) {
// Логіка для реєстрації помилок (наприклад, на сервер)
console.error("Error caught:", error, info);
}
render() {
if (this.state.hasError) {
// Показуємо запасний UI, якщо сталася помилка
return <h1>Щось пішло не так.</h1>;
}
return this.props.children;
}
}
- Використання Error Boundary: Обгортаємо компоненти, які можуть викликати помилки, у
ErrorBoundary
.
const App = () => {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
};
- Запасний інтерфейс: Коли помилка відбувається, в ErrorBoundary можна показати запасний інтерфейс (наприклад, повідомлення про помилку, кнопку для повторної спроби або навіть дії для відновлення додатку).
-
Error Boundary не ловить помилки в обробниках подій (наприклад, onClick), асинхронних кодах, таймерах чи мережевих запитах. Для цих випадків використовуй try-catch або інші механізми.
-
Якщо помилка сталася у самому Error Boundary, вона не буде зловлена.
Error Boundaries корисні для стабільності додатку, дозволяючи перехоплювати та обробляти помилки, не зупиняючи весь додаток.
59. Як використовувати InnerHtml у React?
- У React для вставки HTML-контенту в DOM використовується атрибут dangerouslySetInnerHTML. Це дає можливість вставити HTML безпосередньо в компонент, однак такий підхід може бути небезпечним, тому й називається "dangerously", оскільки він дозволяє вбудовувати сирий HTML, що може призвести до XSS-атак, якщо дані не очищені.
const MyComponent = () => {
const htmlContent = "<p>Це <strong>HTML</strong> контент.</p>";
return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
};
-
dangerouslySetInnerHTML
приймає об'єкт, в якому ключ__html
містить рядок HTML-коду. -
Це дозволяє вбудовувати HTML всередину компонента, але не безпечно, якщо контент надходить з ненадійних джерел.
-
Якщо ви впевнені в безпечності даних (наприклад, від власних серверів).
-
Коли вам потрібно вбудувати динамічний HTML-контент, такий як сторінки чи статті з HTML.
-
Безпека: Ніколи не використовуйте dangerouslySetInnerHTML для вставки даних, отриманих від користувача чи зовнішніх джерел, без попередньої очистки від шкідливих скриптів.
-
Для очищення контенту використовуйте бібліотеки, такі як DOMPurify, щоб уникнути XSS атак.
Приклад очищення даних перед вставкою:
import DOMPurify from "dompurify";
const MyComponent = () => {
const dirtyHtml = "<img src=x onerror=alert('XSS')>";
const cleanHtml = DOMPurify.sanitize(dirtyHtml);
return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
};
Отже, dangerouslySetInnerHTML
слід використовувати обережно і тільки в тих випадках, коли ви впевнені в безпеці контенту.
60. Що таке портали (Portals) у React?
- Портали (Portals) в React дозволяють рендерити дочірні елементи в іншу частину DOM, а не в стандартне місце рендерингу компонента. Це корисно для розміщення елементів, які повинні знаходитися поза звичною ієрархією DOM, наприклад, модальні вікна, тултіп або спливаючі елементи.
-
Вони дають можливість рендерити елементи в інше місце DOM, не порушуючи структуру React-компонентів.
-
Порти можуть бути корисні, коли потрібно рендерити елементи поверх іншого вмісту (наприклад, модальні вікна, спливаючі меню).
- Портал дозволяє відправити вміст в будь-яке місце DOM, навіть поза межами кореневого контейнера React.
import ReactDOM from "react-dom";
const Modal = () => {
return ReactDOM.createPortal(
<div className="modal">
<h1>Це модальне вікно</h1>
</div>,
document.getElementById("modal-root") // Місце в DOM, куди рендеримо портал
);
};
const App = () => {
return (
<div>
<h1>Головна сторінка</h1>
<Modal />
</div>
);
};
-
ReactDOM.createPortal()
: використовується для створення порталу. Перший аргумент — це вміст, який рендериться, а другий аргумент — це DOM-елемент, в який цей вміст вставляється. -
Портали можуть бути використані для модальних вікон, тултіпів, спливаючих меню та інших елементів, які мають бути відображені поза межами основного дерева компонентів.
-
Хоча елементи, що рендеряться через портали, знаходяться поза межами основної ієрархії React-компонентів, вони все одно мають доступ до контексту, стану і пропсів своїх батьків.
-
Порти можуть бути корисні, якщо потрібно обробити випадки, коли елементи повинні бути розташовані "поверх" іншого контенту або на іншому рівні ієрархії DOM (наприклад, модальне вікно, яке не має бути обмежене батьківським контейнером).
Порти дозволяють зберігати логіку компонента і структуру, не порушуючи правила DOM, що дозволяє створювати зручні й чисті UI-компоненти.
61. Що таке компонент-перемикач (Switching Component)?
- Компонент-перемикач (Switching Component) в React — це патерн, коли компонент динамічно рендерить один із своїх дочірніх компонентів на основі певної умови. Це використовується, коли потрібно відображати різні компоненти залежно від стану, маршруту чи отриманих даних.
const SwitchingComponent = ({ type }) => {
switch (type) {
case "success":
return <SuccessMessage />;
case "error":
return <ErrorMessage />;
default:
return <DefaultMessage />;
}
};
const App = () => {
return <SwitchingComponent type="success" />;
};
type
визначає, який компонент буде відображений.
import { Route, Routes } from "react-router-dom";
const App = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="\*" element={<NotFound />} />
</Routes>
);
};
- Тут
Routes
виступає як компонент-перемикач для рендерингу відповідного компонента залежно від URL.
const components = {
success: SuccessMessage,
error: ErrorMessage,
default: DefaultMessage,
};
const SwitchingComponent = ({ type }) => {
const Component = components[type] || components.default;
return <Component />;
};
- Це більш чистий варіант без
switch
.
Компоненти-перемикачі спрощують логіку та роблять код більш читабельним, коли потрібно умовно рендерити різні компоненти.
62. Що таке "опитування" (Polling)? Як його реалізувати у React?
- Опитування (Polling) — це періодичне надсилання запитів до сервера для отримання оновлених даних. Це корисно, коли сервер не підтримує WebSockets або Server-Sent Events, а клієнт має отримувати нову інформацію без необхідності перезавантаження сторінки.
- Опитування можна реалізувати через
setInterval
,setTimeout
або використовуючи React-хуки (useEffect
).
- Використання
setInterval
import { useState, useEffect } from "react";
const PollingComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const response = await fetch("https://api.example.com/data");
const result = await response.json();
setData(result);
};
fetchData(); // Виконати одразу при завантаженні
const interval = setInterval(fetchData, 5000); // Опитування кожні 5 сек.
return () => clearInterval(interval); // Очищення при розмонтуванні
}, []);
return <div>{data ? JSON.stringify(data) : "Завантаження..."}</div>;
};
- fetchData() отримує дані із сервера.
- setInterval запускає опитування кожні 5 секунд.
- clearInterval зупиняє опитування при розмонтуванні.
- Використання
setTimeout
для динамічного інтервалу
- Якщо сервер має обмеження по запитах, краще використовувати setTimeout, щоб уникнути накладання запитів.
const PollingComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
try {
const response = await fetch("https://api.example.com/data");
const result = await response.json();
if (isMounted) setData(result);
} catch (error) {
console.error("Помилка запиту", error);
} finally {
if (isMounted) setTimeout(fetchData, 5000);
}
};
fetchData();
return () => {
isMounted = false; // Запобігає оновленню стану після розмонтування
};
}, []);
return <div>{data ? JSON.stringify(data) : "Завантаження..."}</div>;
};
- Тут setTimeout викликається лише після завершення попереднього запиту, що дозволяє уникнути накладання запитів.
- setInterval підходить для постійного опитування, але може створювати накладення запитів.
- setTimeout дає більше контролю і краще підходить для адаптивного опитування.
- У разі великих навантажень варто розглянути WebSockets або Server-Sent Events.
63. Різниця між елементом та компонентом?
-
Елемент (Element)
- Незмінний (immutable). Його не можна змінити після створення.
- Об'єкт, що описує UI. Це простий об'єкт JavaScript, який React використовує для побудови віртуального DOM.
- Створюється за допомогою JSX або
React.createElement
.
-
Приклад елемента:
const element = <h1>Привіт, світ!</h1>;
Або без JSX:
const element = React.createElement("h1", null, "Привіт, світ!");
-
Це просто опис того, як має виглядати UI.
-
React рендерить його в DOM.
-
Компонент (Component)
- Функція або клас, який повертає елементи.
- Може мати стан (state) і логіку.
- Можна перевикористовувати.
-
Функціональний компонент:
const MyComponent = () => {
return <h1>Привіт, я компонент!</h1>;
};
-
Повертає елемент.
-
Може приймати
props
, мати внутрішню логіку. -
Класовий компонент:
class MyComponent extends React.Component {
render() {
return <h1>Привіт, я класовий компонент!</h1>;
}
}
- Має метод
render()
, що повертає елемент.
Критерій | Елемент | Компонент |
---|---|---|
Що це? | Об'єкт (JSX або React.createElement ) |
Функція або клас |
Чи змінюється? | Ні (immutable) | Так, може мати state |
Чи може мати логіку? | Ні | Так |
Використання | Визначає, що буде рендеритися | Контейнер для елементів та логіки |
-
Простими словами:
- Елемент — це
що рендерити
. - Компонент — це
як і коли рендерити
.
- Елемент — це
64. Як React обробляє чи обмежує використання пропсів певного типу?
- React обмежує використання пропсів певного типу за допомогою
PropTypes
абоTypeScript
.
- Використання PropTypes (вбудована перевірка типів)
import PropTypes from "prop-types";
const MyComponent = ({ name, age, isActive }) => {
return (
<div>
<h1>{name}</h1>
<p>Вік: {age}</p>
<p>{isActive ? "Активний" : "Неактивний"}</p>
</div>
);
};
// Визначення типів пропсів
MyComponent.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
isActive: PropTypes.bool,
};
PropTypes.string.isRequired
— обов’язковий пропс name.PropTypes.number
— age має бути числом.PropTypes.bool
— isActive має бути булевим значенням.
Якщо передані некоректні типи, React видасть попередження в консолі (тільки у режимі розробки).
- Використання TypeScript (строга перевірка на рівні компіляції)
Копіювати;
Редагувати;
type MyComponentProps = {
name: string;
age?: number;
isActive: boolean;
};
const MyComponent: React.FC<MyComponentProps> = ({ name, age, isActive }) => {
return (
<div>
<h1>{name}</h1>
<p>Вік: {age}</p>
<p>{isActive ? "Активний" : "Неактивний"}</p>
</div>
);
};
name: string
— обов’язковий рядковий пропс.age?: number
— необов’язковий числовий пропс.isActive: boolean
— обов’язковий булевий пропс.
TypeScript дає помилку ще до запуску коду, якщо передані неправильні пропси.
Метод | Переваги | Недоліки |
---|---|---|
PropTypes | Простий, працює в JavaScript | Перевіряє лише в runtime, слабка безпека |
TypeScript | Строга типізація, ловить помилки раніше | Потрібна компіляція, складніший синтаксис |
- Якщо проєкт на TypeScript, PropTypes не потрібен. Якщо JavaScript, PropTypes дає базову перевірку.
65. Що таке строгий режим (Strict Mode) React? Його переваги?
-
Strict Mode — це спеціальний інструмент React для виявлення потенційних проблем у коді. Він не впливає на роботу у продакшені, але допомагає покращити якість коду під час розробки.
-
Активується обгорткою компонентів у
<React.StrictMode>
:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Функція | Опис |
---|---|
Виявлення небезпечних методів життєвого циклу | Попереджає про застарілі методи (componentWillMount , componentWillReceiveProps , componentWillUpdate ). |
Двічі викликає функції під час розробки | Допомагає знайти побічні ефекти у useEffect та інших хуках. |
Попереджає про використання застарілого API | Вказує на старі контексти (contextType ) та небезпечні патерни. |
Виявляє непередбачувану поведінку | Наприклад, викликає useEffect двічі, щоб перевірити коректність очистки ефектів. |
- Так, якщо ти хочеш уникнути проблем ще на етапі розробки. Він може трохи дратувати через подвійний рендер, але це допомагає знаходити приховані помилки в коді.
66. Що таке буріння пропсів (Prop Drilling)? Як його уникнути?
-
Prop Drilling — це передача пропсів через кілька рівнів вкладених компонентів, навіть якщо вони потрібні лише в дочірньому компоненті глибше в ієрархії. Це ускладнює підтримку коду та робить його менш читабельним.
-
Приклад Prop Drilling:
const Parent = () => {
const user = { name: "John" };
return <Child user={user} />;
};
const Child = ({ user }) => {
return <GrandChild user={user} />;
};
const GrandChild = ({ user }) => {
return <p>Ім'я: {user.name}</p>;
};
- Тут
user
передається черезChild
, хоча він йому не потрібен — це і є буріння пропсів.
Метод | Опис |
---|---|
Context API | Дозволяє передавати дані безпосередньо потрібним компонентам. |
Зовнішні стейти (Redux, Zustand, Jotai, Recoil) | Використовуються для управління глобальним станом без передачі пропсів. |
Компоненти з рендер-пропсами (Render Props) | Дозволяють передавати функції замість пропсів. |
Custom Hooks | Виносять логіку в окремі функції для доступу до загальних даних. |
import { createContext, useContext } from "react";
const UserContext = createContext();
const Parent = () => {
const user = { name: "John" };
return (
<UserContext.Provider value={user}>
<GrandChild />
</UserContext.Provider>
);
};
const GrandChild = () => {
const user = useContext(UserContext);
return <p>Ім'я: {user.name}</p>;
};
- Тут
user
доступний напряму уGrandChild
, без зайвої передачі черезChild
.
67. Різниця між рендерингом та монтуванням?
- Різниця між рендерингом та монтуванням у React
Процес | Опис |
---|---|
Монтування (Mounting) | Компонент створюється і додається в DOM вперше. Викликаються constructor , render , componentDidMount (у класах) або useEffect з порожнім масивом залежностей (у функціональних компонентах). |
Рендеринг (Rendering) | Виконується виклик render() або повторний виклик функціонального компонента для оновлення вмісту. Відбувається при зміні state , props або виклику forceUpdate() . |
useEffect(() => {
console.log("Компонент змонтовано");
}, []); // Виконається один раз при монтуванні
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Компонент відрендерився");
}); // Виконається при кожному рендері
return <button onClick={() => setCount(count + 1)}>+</button>;
Тут рендер відбувається кожного разу при зміні count
.
68. Що таке події вказівника (Pointer Events)?
- Pointer Events — це API, що об'єднує події миші, сенсорного екрану та стилуса в єдину систему обробки подій.
Подія | Опис |
---|---|
onPointerDown | Спрацьовує при натисканні пальцем, мишею або стилусом. |
onPointerUp | Спрацьовує при відпусканні кнопки миші, пальця або стилуса. |
onPointerMove | Викликається при русі вказівника над елементом. |
onPointerEnter | Спрацьовує, коли вказівник входить у межі елемента. |
onPointerLeave | Спрацьовує, коли вказівник виходить за межі елемента. |
onPointerCancel | Викликається, коли браузер скасовує подію (наприклад, при зміні фокусу). |
const PointerExample = () => {
const handlePointerDown = () => console.log("Вказівник натиснуто");
return (
<div
onPointerDown={handlePointerDown}
style={{ width: 200, height: 200, background: "lightgray" }}
>
Клікни тут
</div>
);
};
- Цей код виведе
"Вказівник натиснуто"
у консоль при натисканні будь-яким пристроєм (миша, сенсор, стилус).
69. Що таке інверсія спадкування (Inheritance Inversion)?
- Інверсія спадкування (Inheritance Inversion) — це ситуація, коли клас, який мав би бути базовим, фактично залежить від його нащадків або втрачає контроль над логікою, що повинна бути у спадковій ієрархії.
-
Порушення принципу Liskov Substitution (LSP).
-
Важко змінювати або розширювати базовий клас без впливу на всі його нащадки.
-
Збільшення складності через взаємозалежності.
class Parent {
method() {
throw new Error("Метод має бути реалізований у нащадку");
}
}
class Child extends Parent {
method() {
return "Реалізація в нащадку";
}
}
- Тут базовий клас не має власної логіки і змушує нащадків реалізовувати поведінку, що є ознакою інверсії спадкування.
class Behavior {
method() {
return "Реалізація без інверсії";
}
}
class Parent {
constructor() {
this.behavior = new Behavior();
}
method() {
return this.behavior.method();
}
}
- Цей підхід усуває залежність батьківського класу від нащадків, роблячи код гнучкішим.
70. Як у React реалізувати двостороннє зв'язування даних?
- У React двостороннє зв’язування даних реалізується через керовані компоненти (controlled components), де стан (
state
) компонента синхронізується з полем вводу (input
).
import { useState } from "react";
const TwoWayBinding = () => {
const [value, setValue] = useState("");
return (
<div>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<p>Введене значення: {value}</p>
</div>
);
};
export default TwoWayBinding;
-
value
зберігає поточний стан введеного значення. -
onChange
оновлює стан при змініinput
. -
Оновлений
value
відображається в інтерфейсі, забезпечуючи двосторонній зв’язок.
- Цей підхід дозволяє контролювати введені дані, робити валідацію та обробку перед оновленням стану.
71. Переваги хуків?
Перевага | Опис |
---|---|
Менше коду | Хуки дозволяють уникнути класів і скоротити обсяг коду. |
Краща читабельність | Код з хуками легший для розуміння та підтримки. |
Повторне використання логіки | Custom Hooks дозволяють повторно використовувати логіку між компонентами. |
Спрощене управління станом | Використання useState і useReducer робить стейт-менеджмент простішим. |
Гнучкість у використанні ефектів | useEffect дозволяє виконувати побічні ефекти без потреби в класових методах життєвого циклу. |
Легша міграція | Полегшує перехід від класових компонентів до функціональних. |
72. Недоліки хуків?
Недолік | Опис |
---|---|
Збільшена кількість ререндерів | Неправильне використання хуків, особливо useEffect , може викликати зайві ререндери. |
Ускладнене розуміння логіки | Логіка компонента може бути розпорошена між кількома useEffect , що ускладнює дебаг. |
Відсутність явного життєвого циклу | На відміну від класових компонентів, хуки не мають чітко виражених методів життєвого циклу. |
Можливі проблеми з оптимізацією | Неправильне використання useCallback і useMemo може призвести до неефективної роботи. |
Складність у великих проєктах | У масштабних додатках хуки можуть ускладнювати управління станом і побічними ефектами. |
73. Правила (обмеження) використання хуків?
Правило | Опис |
---|---|
Використання тільки у функціях | Хуки можна викликати лише у функціональних компонентах або в кастомних хуках. |
Збереження порядку виклику | Хуки не можна викликати умовно (if , for , while ), інакше порушиться порядок виклику. |
Виклик тільки на верхньому рівні | Хуки не можна викликати всередині вкладених функцій або обробників подій. |
Іменування кастомних хуків | Кастомні хуки мають починатися з use (наприклад, useAuth ). |
Дотримання правил залежностей | У useEffect , useMemo та useCallback залежності ([] ) потрібно вказувати правильно, щоб уникнути непередбачуваної поведінки. |
74. Що робить метод, що shouldComponentUpdate?
shouldComponentUpdate
– це метод життєвого циклу у класових компонентах, який визначає, чи потрібно повторно рендерити компонент.
-
За замовчуванням повертає
true
, що означає ререндер при будь-якій змініstate
абоprops
. -
Якщо повертає
false
, React не буде ререндерити компонент, навіть якщо props абоstate
змінилися.
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return nextProps.value !== this.props.value; // Ререндер тільки при зміні value
}
render() {
return <div>{this.props.value}</div>;
}
}
-
Використовуй
React.memo()
для мемоізації. -
useMemo()
іuseCallback()
допомагають оптимізувати ререндери.
75. Що таке useReducer()?
useReducer()
— це хук у React, який використовується для управління станом у функціональних компонентах. Це альтернативаuseState()
, яка підходить для складних логік оновлення стану, особливо якщо зміни залежать від попереднього стану.
const [state, dispatch] = useReducer(reducer, initialState);
-
reducer
— функція, яка приймаєstate
іaction
, повертаючи новий стан. -
initialState
— початковий стан. -
dispatch
— функція для виклику редюсера з певноюaction
.
import { useReducer } from "react";
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}
-
Коли стан має складну логіку або залежності.
-
Коли необхідно уніфікувати оновлення стану через dispatch.
-
Для масштабованості, наприклад, при використанні в глобальному стані.
76. Як реалізувати одноразове виконання операції під час початкового рендерингу?
- Для виконання операції лише один раз під час початкового рендерингу у функціональних компонентах використовуй
useEffect
з порожнім масивом залежностей ([]
):
import { useEffect } from "react";
function MyComponent() {
useEffect(() => {
console.log("Це виконається лише один раз після монтування компонента");
}, []);
return <div>Компонент</div>;
}
useEffect(() => { /_ код _/ }, [])
— пустий масив залежностей означає, що ефект запуститься тільки один раз після першого рендерингу (аналогcomponentDidMount
у класових компонентах).
useEffect(() => {
const interval = setInterval(() => {
console.log("Працює одноразовий ефект");
}, 1000);
return () => clearInterval(interval); // Очистка при розмонтуванні
}, []);
- Цей підхід корисний для ініціалізації API-запитів, підписок, таймерів тощо.
77. Що таке розподілений компонент (Distributed Component)?
- Розподілений компонент (Distributed Component) — це концепція, коли компонент розбивається на кілька незалежних частин, що можуть рендеритися або виконувати логіку окремо, але працюють разом.
- Код-сплітинг (Code Splitting)
- Компоненти вантажаться лише при необхідності, що зменшує початковий розмір бандла.
import { lazy, Suspense } from "react";
const LazyComponent = lazy(() => import("./LazyComponent"));
function App() {
return (
<Suspense fallback={<div>Завантаження...</div>}>
<LazyComponent />
</Suspense>
);
}
- Компоненти-контейнери (Container-Presentational Pattern)
- Виділяє логіку (контейнер) та відображення (презентаційний компонент).
function DataContainer({ children }) {
const [data, setData] = useState(null);
useEffect(() => {
fetch("/api/data")
.then((res) => res.json())
.then(setData);
}, []);
return children(data);
}
function Presentational({ data }) {
return <div>{data ? JSON.stringify(data) : "Завантаження..."}</div>;
}
function App() {
return (
<DataContainer>{(data) => <Presentational data={data} />}</DataContainer>
);
}
- Мікрофронтенди (Micro Frontends)
-
Використання окремих автономних компонентів у різних частинах застосунку.
- Наприклад, різні команди розробляють окремі частини великого проєкту (
React
,Vue
,Angular
) і інтегрують їх разом.
- Наприклад, різні команди розробляють окремі частини великого проєкту (
-
Для оптимізації продуктивності (ліниве завантаження).
-
Щоб спростити підтримку коду (відокремлення логіки).
-
Для масштабованих застосунків (мікрофронтенди).
78. Розкажіть про хуки useCallback(), useMemo(), useImperativeHandle(), useLayoutEffect()?
-
Мемоізує функцію, щоб вона не створювалася заново при кожному рендері. Корисно для передачі колбеків у дочірні компоненти.
-
Приклад:
import { useCallback } from "react";
function MyComponent({ onClick }) {
return <button onClick={onClick}>Натисни</button>;
}
function Parent() {
const handleClick = useCallback(() => {
console.log("Клік");
}, []); // Функція створюється один раз
return <MyComponent onClick={handleClick} />;
}
-
Мемоізує обчислення, щоб не виконувати їх повторно при кожному рендері, якщо залежності не змінилися.
-
Приклад:
import { useMemo } from "react";
function ExpensiveCalculation({ num }) {
const result = useMemo(() => {
console.log("Обчислення...");
return num \* 2;
}, [num]); // Виконується лише при зміні num
return <div>Результат: {result}</div>;
}
-
Дозволяє керувати поведінкою ref у дочірньому компоненті. Використовується разом із forwardRef().
-
Приклад:
import { useRef, useImperativeHandle, forwardRef } from "react";
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => (inputRef.current.value = ""),
}));
return <input ref={inputRef} {...props} />;
});
function Parent() {
const inputRef = useRef();
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Фокус</button>
<button onClick={() => inputRef.current.clear()}>Очистити</button>
</div>
);
}
-
Працює як
useEffect()
, але виконується синхронно після змін в DOM. Корисно для вимірювання або маніпуляцій з DOM перед тим, як браузер малює сторінку. -
Приклад:
import { useLayoutEffect, useRef } from "react";
function LayoutEffectExample() {
const divRef = useRef();
useLayoutEffect(() => {
console.log("Ширина елемента:", divRef.current.offsetWidth);
}, []);
return (
<div ref={divRef} style={{ width: "200px", height: "100px" }}>
Елемент
</div>
);
}
-
useCallback()
— для запам’ятовування функцій. -
useMemo()
— для запам’ятовування обчислень. -
useImperativeHandle()
— для керування ref дочірнього компонента. -
useLayoutEffect()
— коли треба щось зробити перед відображенням змін в DOM (наприклад, вимірювання).
79. Як відрендерити HTML код у React-компоненті?
- Використовуй
dangerouslySetInnerHTML
, але будь обережний — це може призвести до XSS-атак, якщо вставляєш несанітизовані дані.
Копіювати;
Редагувати;
function MyComponent() {
const htmlContent = "<p style='color: red;'>Це HTML-код</p>";
return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
}
- Якщо працюєш з динамічними даними, обов’язково санітизуй їх перед вставкою.
80. Навіщо setState() потрібно передавати функцію?
- Передача функції в
setState()
потрібна, коли новий стан залежить від попереднього. Це гарантує правильне оновлення, оскількиsetState()
виконується асинхронно і може групувати виклики.
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
setCount(count + 1);
}
return <button onClick={increment}>{count}</button>;
}
- Тут
count + 1
обчислюється двічі з тим самим старимcount
, тому кнопка збільшуватиме значення лише на 1, а не на 2.
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);
}
return <button onClick={increment}>{count}</button>;
}
- Тут
setCount()
отримує актуальне значенняprevCount
, тому інкремент працює коректно, збільшуючи значення на 2.
81. Для чого призначений метод registerServiceWorker() у React?
registerServiceWorker()
використовувався для реєстрації Service Worker у Create React App (до видалення з CRA у версії 4).
-
Кешування ресурсів для офлайн-режиму
-
Прискорення завантаження додатка
-
Фонове оновлення ресурсів
import { register } from "./serviceWorker";
register();
-
Після видалення з CRA, Service Worker потрібно налаштовувати вручну через
navigator.serviceWorker.register()
. -
У React 19 немає вбудованого
registerServiceWorker()
, оскільки його видалили ще в React 17 (з Create React App 4). Якщо тобі потрібен Service Worker, реєструй його вручну.
Висновок: у React 19 цей метод більше не актуальний, і Service Worker потрібно налаштовувати самостійно.
82. Чим React Router відрізняється від звичайної маршрутизації?
Критерій | React Router | Звичайна маршрутизація (Server-Side Routing) |
---|---|---|
Тип маршрутизації | Клієнтська (SPA) | Серверна (MPA) |
Перехід між сторінками | Без перезавантаження сторінки (JS оновлює URL) | Перезавантаження сторінки при кожному переході |
Швидкість | Швидший, оскільки не перезапитує сервер | Повільніший через нові HTTP-запити |
SEO | Гірший без SSR (але Next.js вирішує проблему) | Кращий, оскільки контент завантажується із сервера |
Обробка даних | Динамічний рендеринг компонентів | Завантаження HTML зі сторони сервера |
Налаштування | Потрібен React Router | Використовує стандартні можливості сервера |
83. Як передавати пропси в React Router?
- Щоб передати пропси в компоненти при використанні React Router, є кілька підходів:
- Використання компоненту Route для передачі пропсів:
- Можна передавати пропси через компонент Route за допомогою
render
абоchildren
.
import { Route } from "react-router-dom";
<Route
path="/profile"
render={(props) => <Profile {...props} user="John" />}
/>;
- Тут ми передаємо додаткові пропси до компонента
Profile
.
- Використання useNavigate() для передачі даних через навігацію (за допомогою state):
- При переході на нову сторінку можна передавати пропси через
state
.
import { useNavigate } from "react-router-dom";
function Home() {
const navigate = useNavigate();
function goToProfile() {
navigate("/profile", { state: { user: "John" } });
}
return <button onClick={goToProfile}>Go to Profile</button>;
}
import { useLocation } from "react-router-dom";
function Profile() {
const location = useLocation();
const user = location.state?.user;
return <div>Welcome, {user}</div>;
}
- Використання useParams() для доступу до параметрів маршруту:
- Якщо потрібно передати параметри через URL, можна використовувати
useParams()
.
import { useParams } from "react-router-dom";
function Profile() {
const { id } = useParams();
return <div>User ID: {id}</div>;
}
-
render
абоchildren
підходять для передачі пропсів безпосередньо. -
useNavigate()
таstate
дозволяють передавати дані між сторінками. -
useParams()
зручний для динамічних параметрів в URL.
84. Що таке Reselect та як він працює?
- Reselect — це бібліотека для створення ефективних селекторів у Redux. Вона допомагає оптимізувати отримання даних зі стану та уникати непотрібних рендерів компонентів за допомогою мемоізації.
- Reselect використовує мемоізацію, щоб повторно використовувати результати обчислень, якщо вхідні дані не змінилися.
-
Приймає "input селектори", які отримують дані зі стану.
-
Обчислює значення на основі отриманих даних.
-
Кешує результат, щоб не виконувати обчислення при однакових вхідних значеннях.
import { createSelector } from "reselect";
// Вхідний селектор отримує всі користувачі
const selectUsers = (state) => state.users;
// Вхідний селектор отримує активний фільтр
const selectFilter = (state) => state.filter;
// Мемоізований селектор фільтрує користувачів
export const selectFilteredUsers = createSelector(
[selectUsers, selectFilter],
(users, filter) => users.filter((user) => user.role === filter)
);
🔹 Без Reselect компонент перевіряв би весь масив users при кожному рендері. 🔹 З Reselect селектор виконується тільки тоді, коли users або filter змінюється.
✅ Зменшує кількість зайвих викликів mapStateToProps. ✅ Уникає непотрібних рендерів компонентів. ✅ Легко комбінується з Redux. ✅ Покращує продуктивність.
85. Які типи даних може повернути render?
- Метод
render()
у React може повертати:
- JSX або React-елемент
render() {
return <div>Hello, World!</div>;
}
- Масив елементів (фрагментований рендеринг)
render() {
return [
<li key="1">Item 1</li>,
<li key="2">Item 2</li>
];
}
- Фрагменти (React.Fragment)
render() {
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
}
- null (нічого не рендерити)
render() {
return null;
}
- Булеві значення (ігноруються)
render() {
return false; // Нічого не відобразиться
}
- Текстові значення (рендеряться як текст)
render() {
return "Hello, World!";
}
- Портали (рендер у DOM-елемент поза батьківським компонентом)
import { createPortal } from "react-dom";
render() {
return createPortal(<div>Modal</div>, document.getElementById("modal-root"));
}
🚀 Висновок: Основний варіант — JSX або React-елементи, але можна повертати масиви, фрагменти, null, текст або рендерити через портали.
86. Різниця між memo і useMemo?
Критерій | memo | useMemo |
---|---|---|
Що це? | Функція вищого порядку (HOC) | Хук |
Призначення | Запобігає повторному рендеру компонента, якщо пропси не змінилися | Запам’ятовує результат обчислення між рендерами |
Де використовується? | Обгортає компонент | Всередині компонента |
Приклад використання | export default memo(MyComponent); |
const value = useMemo(() => compute(), [deps]); |
Що кешує? | Весь компонент | Результат функції |
Коли застосовувати? | Якщо компонент рендериться з тими ж пропсами без змін | Якщо обчислення ресурсозатратне і залежить від змінних |
-
memo
— коли компонент отримує однакові пропси і його ререндер не потрібен. -
useMemo
— коли потрібно зберігати результат обчислення, щоб не перераховувати його кожен раз.
87. Що таке синтетичні події (SyntheticEvent) у React?
- SyntheticEvent у React — це обгортка над нативними подіями браузера, яка забезпечує кросбраузерну сумісність і покращує продуктивність.
-
Працює однаково у всіх браузерах.
-
Використовує пулізацію (event pooling), що запобігає утриманню зайвих об'єктів у пам’яті.
-
Всі події нормалізовані та мають однакові властивості незалежно від браузера.
function MyComponent() {
const handleClick = (event) => {
console.log(event.type); // "click"
console.log(event.nativeEvent); // Оригінальна подія браузера
};
return <button onClick={handleClick}>Натисни</button>;
}
-
event.preventDefault()
— запобігає стандартній поведінці. -
event.stopPropagation()
— зупиняє спливання події. -
event.persist()
— вимикає пулізацію, щоб подія не скидалася.
88. Чи є React реактивним?
- React не є чисто реактивною бібліотекою, як, наприклад, Vue або Svelte. Однак React має деякі характеристики, які роблять його схожим на реактивні фреймворки:
-
Автоматичне оновлення UI: React оновлює UI (інтерфейс) автоматично, коли змінюється стан (state) або пропси компонента, що нагадує реактивні підходи. Це відбувається через процес рендерингу та порівняння змін.
-
Функціональні компоненти і хуки: Використання хуків, таких як
useState
,useEffect
, створює ефект реактивності, де зміни в стані або пропсах приводять до повторного рендеру компонентів. -
Часткова реактивність: React виконує перерендер тільки тих компонентів, чий стан чи пропси змінилися, що є підходом до реактивності, але на відміну від інших фреймворків, React не обробляє залежності або значення з автоматичними спостерігачами.
- Отже, React має деякі реактивні принципи, але не є повністю реактивним фреймворком.
89. Техніки оптимізації перфомансу React?
- Мемоізація компонентів
- Використовуйте
React.memo()
для запобігання зайвим ререндерам. useMemo()
для кешування обчислень.useCallback()
для збереження стабільності функцій.
- Оптимізація ререндеру
- Уникайте зайвих станів (
useState
) і пропсів. - Використовуйте
shouldComponentUpdate
,React.PureComponent
у класових компонентах. - Оптимізуйте контекст (
Context API
) – не передавайте зайві значення. - Селектори (
Reselect
,Zustand
,Jotai
) для мінімізації оновлень.
- Віртуалізація списків
react-window
,react-virtualized
для відображення лише видимих елементів.
- Кешування та дебаунс
useMemo()
таuseCallback()
для важких обчислень.- Дебаунс (
lodash.debounce
) або тротлінг (lodash.throttle
) для введення користувача.
- Ліниве завантаження (Lazy Loading)
React.lazy()
+Suspense
для поділу коду.- Динамічний імпорт модулів (
import()
).
- Уникнення зайвих ефектів в useEffect
- Передавайте залежності правильно.
- Використовуйте
useRef
для збереження значень без ререндеру.
- Оптимізація зображень
- Використовуйте
next/image
у Next.js. - Оптимізуйте розміри та формати (
WebP
,AVIF
).
- Оптимізація React Router
- Використовуйте
React.lazy()
для сторінок. - Уникайте зайвого ререндеру шляхом коректного оновлення стану.
- Розділення стану
- Використовуйте локальний state там, де не потрібен глобальний.
- Виносьте глобальні зміни у
Redux/Zustand/Recoil
.
- Використання Web Workers
- Для важких обчислень, щоб не блокувати головний потік.
90. Найкращі практики безпеки в React?
- Запобігання XSS (Cross-Site Scripting):
- Завжди очищуйте дані, що надходять від користувача, перед їх відображенням у компоненті.
- Використовуйте JSX (React автоматично очищає вводи, але слід уникати використання
dangerouslySetInnerHTML
). - Якщо потрібно використовувати
dangerouslySetInnerHTML
, переконайтеся, що вміст надійно очищений.
- Уникайте ін'єкцій коду:
- Ніколи не передавайте дані без перевірки у
eval()
,setTimeout()
,setInterval()
або інші функції, які виконують код. - Для динамічного імпорту використовуйте функціональність з вбудованим контролем (наприклад,
React.lazy()
).
- Безпечний доступ до API:
- Використовуйте HTTPS для захисту даних, що передаються через мережу.
- Використовуйте автентифікацію та авторизацію, а також захищені куки (HTTPOnly, Secure).
- Захист від CSRF (Cross-Site Request Forgery):
- Використовуйте токени CSRF для перевірки всіх запитів, які змінюють дані на сервері.
- Використовуйте флаг
SameSite
для cookies, щоб обмежити доступ до них тільки на тому ж домені.
- Контроль доступу:
- Перевіряйте, чи є в користувача права на виконання запитуваної дії перед тим, як відправити запит на сервер.
- Не довіряйте клієнтським перевіркам. Всі перевірки на сервері повинні бути остаточними.
- Захист від відкритих редагувальних полів:
- Для форм і полів, що приймають дані від користувачів, встановлюйте обмеження на допустимі значення.
- Оновлення залежностей:
- Регулярно перевіряйте і оновлюйте залежності для виявлення потенційних вразливостей. Використовуйте
npm audit
або інші інструменти для цього.
- Керування секретами:
- Не зберігайте секрети (API-ключі, паролі тощо) в клієнтському коді. Вони повинні бути на сервері або в середовищах, таких як перемінні оточення.
- Використання Content Security Policy (CSP):
- Використовуйте CSP для запобігання виконанню небажаних скриптів на вашому сайті.
- Захист від Clickjacking:
- Використовуйте заголовки
X-Frame-Options
абоContent-Security-Policy
для запобігання вашому сайту бути вбудованим в<iframe>
на інших веб-сайтах.
Дотримання цих практик допоможе знизити ризики безпеки в React-додатках.