DidChangeDependencies and DidUpdateWidget in Flutter

What are these similar-looking Flutter Lifecycle callbacks?

DidChangeDependencies and DidUpdateWidget in Flutter
Sorce

FLUTTER

DidChangeDependencies and DidUpdateWidget in Flutter

If you’ve been around Flutter long enough to dive into the StatefulWidget lifecycle, you’ve probably seen two eerily similar methods: didChangeDependencies and didUpdateWidget.

They sound like they do the same thing.

They’re both lifecycle callbacks.

And they both seem to react to “something changing.”

But here’s the twist: they don’t fire for the same reasons. And mixing them up can lead to unnecessary rebuilds or even confusing bugs.

Let’s break this down — not as another dry documentation dump, but as a story of when, why, and how these two callbacks come into play.

First: Why do lifecycle methods even exist?

Flutter’s rendering system is declarative. That means your widget tree reacts to state, not imperative calls. So when something changes — like a theme, a localisation setting, or a parent rebuild — you sometimes need to respond.

And that’s where lifecycle callbacks come in.

Meet didChangeDependencies: the Context Listener

Think of didChangeDependencies as your go-to place for reacting to changes in inherited widgets.

It runs:

• After initState (once)

• Whenever an InheritedWidget it depends on changes

Common use case:

@override 
void didChangeDependencies() { 
  super.didChangeDependencies(); 
  final locale = Localizations.localeOf(context); 
  print('Locale changed: $locale'); 
}

So if the app’s locale changes (say, English to Spanish), your widget can react accordingly — maybe reload some data or update labels.

Gotcha:

It gets called more often than you expect, especially if your widget depends on inherited widgets like Theme, MediaQuery, Localisations, etc.

So don’t put expensive logic here unless you memoise or debounce it.

Now, meet didUpdateWidget: the Props Comparator

This one’s more specific. It’s called only when the widget is rebuilt with a new configuration, but the same runtime type and still mounted in the tree.

It runs:

• Whenever the Widget is updated (i.e. build() is called again)

But only if the parent passed in a new widget with different fields

Common use case:

@override 
void didUpdateWidget(covariant MyWidget oldWidget) { 
  super.didUpdateWidget(oldWidget); 
  if (widget.userId != oldWidget.userId) { 
    _loadUser(widget.userId); 
  } 
}

This is useful if your widget receives props (such as userId) from its parent and the parent rebuilds it with new values.

didUpdateWidget lets you respond to those changes without needing to dispose of and recreate the widget.

TL;DR: Who listens to what?

Real-world analogy

Imagine you’re an employee at a company.

• didChangeDependencies is like HR emailing that the company policy has changed. You need to re-read it and possibly adjust your approach.

• didUpdateWidget is your manager changing your role or project. You’re still employed, still in the org chart — but with a new focus.

Should I use both?

Sometimes, yes.

Let’s say you’re building a widget that:

  • Takes the userId as a parameter from its parent
  • Also depends on Theme.of(context) for styling

Then you’d likely use:

  • didUpdateWidget to fetch data when the userId changes
  • didChangeDependencies to update styles or re-render when the theme changes

Keeping their responsibilities separate keeps your logic clean and avoids over-rebuilding.

One last thing…

Don’t forget that didChangeDependencies is always called after initState. So if you’re initialising something that depends on context (like inherited widgets), don’t do it in initState — use didChangeDependencies instead.

@override 
void initState() { 
  super.initState(); 
  // DON’T access Theme.of(context) here 
} 
 
@override 
void didChangeDependencies() { 
  super.didChangeDependencies(); 
  final theme = Theme.of(context); // YES 
}

Final takeaway

In Flutter, lifecycle callbacks aren’t just technical details — they’re powerful tools when used right. But using the wrong one in the wrong place? That’s a subtle trap.

So next time you’re wiring up a StatefulWidget, pause for a second.

Ask yourself:

Am I reacting to context? Or to new props?

Let that answer guide you to either didChangeDependencies or didUpdateWidget.