Ответ
didUpdateWidget — это метод жизненного цикла объекта State, который вызывается, когда родительский виджет перестраивается и передает новый экземпляр StatefulWidget с тем же runtimeType и Key. Этот метод позволяет сравнить старый и новый виджеты и при необходимости синхронизировать внутреннее состояние или выполнить побочные эффекты.
Типичный сценарий использования: обновление слушателей или контроллеров при изменении входных параметров виджета.
Пример: Виджет, который подписывается на Stream, идентификатор которого может измениться.
class UserDataWidget extends StatefulWidget {
final String userId;
const UserDataWidget({required this.userId, Key? key}) : super(key: key);
@override
_UserDataWidgetState createState() => _UserDataWidgetState();
}
class _UserDataWidgetState extends State<UserDataWidget> {
StreamSubscription? _userDataSubscription;
UserData? _currentData;
void _subscribeToUserData(String userId) {
// Отписываемся от старой подписки
_userDataSubscription?.cancel();
// Подписываемся на новый поток данных пользователя
_userDataSubscription = userRepository.getUserStream(userId).listen((data) {
setState(() => _currentData = data);
});
}
@override
void initState() {
super.initState();
_subscribeToUserData(widget.userId); // Первоначальная подписка
}
@override
void didUpdateWidget(UserDataWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// Если userId изменился, обновляем подписку
if (oldWidget.userId != widget.userId) {
_subscribeToUserData(widget.userId);
}
}
@override
void dispose() {
_userDataSubscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text(_currentData?.name ?? 'Загрузка...');
}
}
Важно: didUpdateWidget вызывается перед build. В нем можно вызывать setState(). Для первоначальной инициализации используйте initState.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Сейчас объясню на пальцах, чтобы даже мартышлюшка поняла.
Вот представь: у тебя есть StatefulWidget, который как коробка с динамиками. Внутри неё сидит State — это как твой личный диджей, который музыку ставит. Так вот, didUpdateWidget — это тот момент, когда тебе, диджею, приносят новую коробку (виджет перестроился), но говорят: «Сиди на том же месте, чувак, просто коробка теперь другого цвета».
И ты, такой: «Окей, дай-ка я гляну, что в этой новой коробке поменялось». Берёшь, сравниваешь старую и новую. Если, например, в старой коробке был вход для AUX, а в новой — для Bluetooth, то ты, блядь, должен отключить старый провод и подключиться по новой технологии. А если ничего не поменялось — ну и хуй с ним, сиди дальше, верти пластинки.
Зачем это вообще нужно? Ну, например, когда у тебя виджет подписан на какой-то поток данных, а параметр для подписки (типа userId) прилетел новый. Если не отследить это изменение — будешь слушать не того пользователя, доверия ебать ноль.
Смотри, как это выглядит в коде, на примере виджета, который показывает данные юзера:
class UserDataWidget extends StatefulWidget {
final String userId; // Сюда может прилететь новый айдишник
const UserDataWidget({required this.userId, Key? key}) : super(key: key);
@override
_UserDataWidgetState createState() => _UserDataWidgetState();
}
class _UserDataWidgetState extends State<UserDataWidget> {
StreamSubscription? _userDataSubscription; // Наша подписка на поток
UserData? _currentData; // Текущие данные
// Метод, который подписывается на данные пользователя
void _subscribeToUserData(String userId) {
// Сначала отписываемся от старого говна, если оно было
_userDataSubscription?.cancel();
// Теперь подписываемся заново, на нового юзера
_userDataSubscription = userRepository.getUserStream(userId).listen((data) {
setState(() => _currentData = data); // Получили данные — обновились
});
}
@override
void initState() {
super.initState();
// При самом первом создании — подписываемся
_subscribeToUserData(widget.userId);
}
@override
void didUpdateWidget(UserDataWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// А ВОТ ТУТ МАГИЯ! Сравниваем: если айдишник в новом виджете отличается от старого...
if (oldWidget.userId != widget.userId) {
// ...то надо переподписаться, ёбана рот!
_subscribeToUserData(widget.userId);
}
// Если не изменился — просто идём дальше, не дергаемся.
}
@override
void dispose() {
// Когда виджет убивают — отписываемся, чтобы память не текла
_userDataSubscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text(_currentData?.name ?? 'Загрузка...');
}
}
Важный момент на миллион, чтобы не обосраться: didUpdateWidget вызывается ДО метода build. И да, внутри него можно спокойно вызывать setState(), если надо. А для самой первоначальной инициализации, когда виджет только-только родился, используй initState — это как твой день рождения, всё происходит один раз.