Strict mode і подвійний рендер
Коротка відповідь
React спеціально робить подвійний рендер у дев-режимі, щоб допомогти тобі виявити помилки і побічні ефекти (side effects) у функціях компонентів, які не повинні впливати на результат рендера.
Ця поведінка увімкнена тільки в режимі розробки, і не відбувається в продакшені.
Хто "винен" - Strict Mode
Подвійний рендер у React Dev відбувається через компонент
<React.StrictMode>,
який за замовчуванням обгортає весь застосунок у create-react-app, Next.js та інших CLI.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);Що робить StrictMode
React.StrictMode - це інструмент для розробників, який:
- Викликає компоненти двічі (в dev) → щоб перевірити, чи немає побічних ефектів у їхньому тілі.
- Викликає
useEffectіuseLayoutEffectдвічі → щоб переконатися, що cleanup працює коректно. - Викликає
constructor,render,useMemo,useCallback,useStateтощо двічі → з метою тестування чистоти функцій.
Що таке "чиста функція" у контексті React
Компонент React - це чиста функція від своїх props і state: вона повинна повертати один і той самий JSX при однакових вхідних даних і не викликати побічні ефекти (запити, таймери, мутації тощо) у тілі самої функції.
Приклад "брудного" компонента:
function Timer() {
console.log('Запуск таймера');
setInterval(() => console.log('tick'), 1000);
return <p>Таймер</p>;
}Тут побічний ефект (setInterval) викликається прямо під час рендера.
React при подвійному виклику покаже, що:
- створюється два таймери,
- і один з них не очищається - що є помилкою логіки.
Приклад подвійного рендера
function Example() {
console.log('Рендер компонента');
return <div>Hello</div>;
}У дев-режимі ти побачиш у консолі:
Рендер компонента
Рендер компонентаА в продакшені (або якщо прибрати <StrictMode>) - тільки один виклик.
Навіщо React робить це
| Мета | Що перевіряє |
|---|---|
| Перевірити чистоту компонентів | Чи немає побічних ефектів при рендері |
| Перевірити коректність cleanup в ефектах | useEffect і useLayoutEffect викликаються двічі |
| Допомогти відловити помилки до продакшену | Наприклад, витоки пам'яті, дублюючі підписки |
| Попередити антипатерни | Виклики API, таймери, мутації в тілі компонента |
Які саме методи React дублює
У StrictMode (тільки dev):
- Викликаються повторно:
- функції компонентів;
useState(ініціалізація);useReducer(ініціалізація);useMemo(ініціалізація);useEffect(mount → unmount → mount);useLayoutEffect(аналогічно).
- Не викликаються повторно:
componentDidCatch;getDerivedStateFromError(щоб не ламати обробку помилок);- події і реальні DOM-операції (вони виконуються один раз).
Як це виглядає покроково
- React викликає компонент → робить "віртуальний" рендер.
- Одразу ж розмонтовує його (викличе cleanup ефектів).
- Знову монтує його з нуля.
Все це відбувається в пам'яті, без повторної зміни DOM, тому інтерфейс не "блимає" - тільки консоль покаже повторні виклики.
Як вимкнути подвійний рендер
Щоб тимчасово прибрати подвійні виклики - просто прибери StrictMode:
root.render(
// Без <React.StrictMode>
<App />
);Але це не рекомендується:
StrictMode допомагає виявити помилки ще до продакшену. Краще виправити код, щоб він був "чистим".
Як писати код, що правильно працює в StrictMode
Дозволено:
function Component() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(id); // cleanup!
}, []);
return <div>{count}</div>;
}Не можна:
function Component() {
// Побічний ефект у тілі функції
setInterval(() => console.log('tick'), 1000);
return <div>Hello</div>;
}Підсумок
| Питання | Відповідь |
|---|---|
| Чому подвійний рендер? | Через <React.StrictMode> |
| Коли відбувається? | Тільки в dev-режимі |
| Навіщо це потрібно? | Щоб знаходити побічні ефекти і помилки в компонентах |
| Чи відбувається в продакшені? | Ні |
| Як вимкнути? | Прибрати <React.StrictMode> (але краще не варто) |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.