Hot Reload — технологія, що дає змогу оновлювати код працюючого мобільного застосунку без перезапуску та втрати поточного стану. Розробник змінює вихідний код — за секунду зміни відображаються на екрані пристрою або емулятора. Це ключова особливість Flutter та React Native, яка радикально прискорює ітерації розробки: час циклу правка-перегляд скорочується з 5–10 секунд (перескладання) до 300–500 мілісекунд. За даними Flutter Documentation, 2025, hot reload виконує інкрементальну компіляцію зміненого коду та надсилає оновлення в Dart VM.
Головне
Hot Reload — механізм розробки, за якого вихідний код змінюється та застосовується до вже запущеного застосунку без його зупинки. Розробник редагує файл, зберігає його, і через 0.3–2 секунди оновлений інтерфейс відображається на екрані. Стан застосунку (лічильники, scroll position, введені дані) зберігається — розробник не втрачає контекст.
Концепція hot reload виникла в ранніх веб-інструментах (LiveReload, 2010) і була адаптована для мобільної розробки фреймворками Flutter (2017) та React Native (2015). Сьогодні hot reload — обов'язкова функція сучасних мобільних фреймворків, поряд із debug-конфігурацією та профілюванням. Без hot reload розробка UI вважається неефективною: кожен перегляд зміни потребує 10–30 секунд на перескладання та запуск.
Технічно hot reload складається з трьох кроків: виявлення зміни (file watcher), компіляція зміненого коду (incremental compiler) та застосування (hot patching). Кожен фреймворк реалізує ці кроки по-своєму, але результат однаковий: мінімальна затримка між правкою та відображенням.
Hot Reload у Flutter побудований на архітектурі Dart VM та JIT-компіляції. Коли розробник натискає «Hot Reload» в IDE або зберігає файл, Flutter виконує інкрементальну компіляцію змінених бібліотек Dart у kernel-файли (.dill). Dart VM завантажує ці файли та замінює реалізації змінених функцій у працюючому застосунку.
// Flutter віджет зі станом, що зберігається при hot reload
class CounterWidget extends StatefulWidget {
@override
State createState() => _CounterState();
}
class _CounterState extends State {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Лічильник: $_counter'),
ElevatedButton(
onPressed: () => setState(() => _counter++),
child: Text('Збільшити'),
),
],
);
}
}
У прикладі StatefulWidget CounterWidget зберігає поле _counter під час hot reload. Dart VM перестворює стан (State), викликаючи reassemble(), але не обнуляє _counter — значення зберігається, якщо віджет не перестворюється повністю. Flutter викликає reassemble() для всіх State-об'єктів, і build() запускається знову з актуальним кодом та збереженим станом.
Коли hot reload не працює: якщо змінено статичну змінну ініціалізації (static const), глобальну змінну, main(), оголошення класу enum/mixin, код у @override initState(). У цих випадках потрібен Hot Restart. За даними Flutter Team (2025), hot reload успішний у 85–90% випадків; 10–15% змін потребують повного перезапуску.
Dart VM у debug-режимі працює як JIT-компілятор: вона інтерпретує Dart-код через kernel-формат (аналог байт-коду). Hot reload завантажує новий kernel-файл і замінює старі визначення функцій. VM не перезапускає ізоляти (isolates) — всі асинхронні операції (Future, Stream) продовжують працювати. У release-режимі Dart компілюється AOT (dart2native), і hot reload недоступний.
Fast Refresh (раніше Hot Reloading) у React Native використовує Metro bundler — JavaScript-модульний бандлер, який відстежує зміни файлів. Коли розробник зберігає файл, Metro компілює лише змінений модуль (HMR — Hot Module Replacement) і надсилає оновлення через WebSocket у працюючий застосунок.
// React Native компонент зі збереженням стану при hot reload
import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<View>
<Text>Счётчик: {count}Text>
<Button title="Збільшити"
onPress={() => setCount(c => c + 1)} />
View>
);
};
Fast Refresh зберігає React-стан (useState, useReducer) при оновленні модуля. Metro HMR передає лише diff зміненого модуля — не весь бандл. React Native використовує React Fast Refresh, розроблений командою React (Dan Abramov, 2019): він генерує новий render для компонента, але зберігає hook-стани та props, якщо сигнатура компонента не змінилася.
Fast Refresh не працює при зміні: експорту компонента, хуків (useEffect, useMemo), модульних залежностей і нативних модулів (Java/Objective-C). Для таких змін потрібен Reload (повне перезавантаження JS-бандла) або Rebuild (перескладання нативного коду). Час fast refresh — 200–800 мс, повний reload — 2–5 секунд.
Hot Reload та Hot Restart — два режими оновлення коду з різними сценаріями застосування. Hot Reload підходить для змін UI (стилі, розмітка, кольори, тексти), коли структура класів і тип стану не змінюються. Hot Restart необхідний при зміні сигнатур методів, додаванні нових віджетів/компонентів у кореневе дерево, зміні initState та нативних модулів.
| Характеристика | Hot Reload | Hot Restart |
|---|---|---|
| Швидкість | 0.3–2 секунди | 2–10 секунд |
| Збереження стану | Так (змінні, state, navigation stack) | Ні (застосунок запускається заново) |
| Компіляція | Інкрементальна (лише зміни) | Повна перекомпіляція Dart/JS |
| Коли використовувати | UI-твіки, стилі, тексти, layout | Зміна структури, нові модулі, нативний код |
| Flutter | Hot Reload (R) | Hot Restart (Shift + R) |
| React Native | Fast Refresh | Reload (Cmd + R) |
Рекомендована стратегія: починати з hot reload. Якщо зміни не застосувалися (IDE показує «Reload needed») — виконати hot restart. У Flutter іконка кнопки змінюється: блискавка (⚡) для hot reload, перекреслена блискавка — якщо потрібен restart. Ефективність розробки з hot reload на 40–60% вища порівняно з повними перескладаннями (дані JetBrains Developer Survey 2024).
Ін'єкція коду (code injection) — загальний механізм hot reload, що використовується всіма фреймворками. Він включає три фази. Перша — виявлення зміни: file watcher (вбудований в IDE) або файлова система (FSNotify) фіксує зміну .dart, .js, .tsx файлу. Друга — компіляція: інкрементальний компілятор перетворює лише змінений файл у проміжне представлення (kernel .dill для Dart, HMR-модуль для JS). Третя — застосування: новий код передається на пристрій і замінює старі визначення в пам'яті працюючого застосунку.
Гаряча заміна функцій (hot patching) — техніка, за якої runtime замінює покажчик на функцію (function pointer) у таблиці віртуальних методів. Dart VM використовує ClassTable — внутрішню структуру, що містить всі завантажені класи. При hot reload VM знаходить клас у ClassTable та замінює його визначення функцій на нові з kernel-файлу. Всі існуючі екземпляри класу автоматично отримують нову поведінку.
// Flutter: reassemble callback для керування станом після hot reload
class MyWidget extends StatefulWidget {
@override
State createState() => _MyState();
}
mixin ReloadAware on State {
@override
void reassemble() {
super.reassemble();
// Скидання кешу або даних після hot reload
clearCache();
}
}
У прикладі mixin ReloadAware перевизначає метод reassemble(), який Dart VM викликає на кожному State-об'єкті після hot reload. Розробник може скинути кеш, переініціалізувати ресурси або виконати міграцію стану. Без цього методу старі дані можуть залишитися в кеші та викликати невідповідність після оновлення віджетів.
Гаряча заміна не працює для змін, що потребують перерозподілу пам'яті під нові поля, зміни типу змінної в класі, додавання нових полів у StatefulWidget, зміни значень enum або generic-параметрів. Ці зміни несумісні з існуючими об'єктами в пам'яті — Dart VM не може «перетасувати» поля у вже виділених об'єктах. Для таких випадків потрібне гаряче перезавантаження (hot restart) або повне перескладання.
Нативна Android та iOS розробка традиційно не має повноцінного hot reload. Android Studio з Android 11+ та AGP 4.2+ підтримує Apply Changes: оновлення коду без перезапуску застосунку. Apply Changes працює через Android Runtime (ART) — він замінює реалізації методів у dex-файлах на льоту. Однак Apply Changes обмежений: не працює для змін ресурсів (layout.xml, drawable), маніфесту та нативних бібліотек.
Apple представила Previews (SwiftUI Preview) у Xcode 15 (2023) — це не hot reload у класичному розумінні. Previews компілюють прев'ю-секцію окремо від основного застосунку та показують результат у canvas'і Xcode. При збереженні файлу Preview оновлюється за 1–3 секунди, але стан застосунку не зберігається. Для UIKit проєктів hot reload доступний через сторонні інструменти: InjectionIII (John Holdsworth) та SwiftHotReload.
Kotlin Multiplatform (KMP) з 2024 року отримав експериментальну підтримку hot reload від JetBrains. Механізм заснований на Kotlin/Native runtime із заміною функцій в об'єктному файлі (.klib). JetBrains Compose Multiplayer використовує свою реалізацію hot reload, аналогічну Flutter: інкрементальна компіляція та заміна класів у Kotlin/Native runtime. Швидкість — 1–3 секунди, доступно лише для UI-змін.
Apply Changes — механізм Android Studio, що використовує ART runtime API. При збереженні коду Android Studio визначає, які класи змінилися, і надсилає їх dex-файли на пристрій через adb. ART замінює реалізації методів у запущеному застосунку без зупинки. Apply Changes працює в трьох режимах: Instant Run (швидка заміна методу), Swap (заміна класу з перестворенням екземплярів) та Restart Activity (якщо зміни несумісні з поточним станом).
Часті запитання
Hot Reload оновлює код без перезапуску застосунку та зберігає стан. Live Reload перезавантажує весь застосунок або веб-сторінку цілком при зміні файлів. Live Reload простіший у реалізації, але повільніший і втрачає стан. Flutter та React Native використовують hot reload, веб-інструменти — live reload.
Hot Reload не працює при змінах, що потребують перерозподілу пам'яті (нові поля класу), зміни статичних констант (static const), перейменування віджетів, зміни enum або generic-параметрів. Ці зміни несумісні з існуючими об'єктами в пам'яті Dart VM або JavaScript runtime.
Так, hot reload працює і на фізичному пристрої, і на емуляторі. Flutter передає kernel-файли на пристрій через USB (adb forward) або Wi-Fi. React Native використовує WebSocket через metro bundler. Затримка на фізичному пристрої зазвичай на 10–30% вища, ніж на емуляторі.
Xcode Previews (з 2021) — аналог hot reload для SwiftUI, але з обмеженнями: прев'ю компілюється окремо, не підтримує навігацію по застосунку та складні стани. Apple не надає офіційний hot reload для iOS. Сторонні інструменти: InjectionIII та SwiftHotReload використовують Objective-C Runtime для ін'єкції коду.
Якщо після hot reload UI відображається некоректно: виконати hot restart. Якщо проблема в даних — перевірити reassemble()-callback у Flutter або useEffect cleanup у React Native. Для постійних проблем використовувати Flutter Clean або Reset Metro Cache. Якщо баг відтворюється лише після reload — це ознака несумісності змін з існуючим станом.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також