How do you avoid unnecessary widget rebuilds in Flutter?
Short Answer
Scope state narrowly (so only the widgets that depend on it rebuild), use `const` constructors wherever possible, and split large build methods into smaller widgets so a change in one part doesn't force the whole tree to re-render.
The single biggest cause of unnecessary rebuilds is calling `setState()` (or having a `Provider`/`Riverpod` watcher) high up in a large widget tree, which forces everything below it to rebuild even if only a small piece actually changed visually. The fix is to push state down: extract the part of the UI that actually changes into its own small widget, and keep state management scoped to just that subtree.
For Provider/Riverpod specifically, prefer `Selector`/`Consumer` (or `ref.watch(provider.select(...))` in Riverpod) to listen to only the specific field you need, rather than the whole object. Also use `const` constructors aggressively, and avoid creating new closures or objects inline inside `build()` (e.g. a new `BoxDecoration` every build) since that defeats Flutter's ability to detect "nothing changed."
Common Mistakes
- ×Wrapping the entire `Scaffold` in a `Consumer`/`Obx` instead of just the small widget that needs the data.
- ×Creating new callback closures or styling objects inline on every build instead of hoisting them out.
Related Questions
Why should you use const widgets in Flutter?
A `const` widget is created once at compile time and reused across rebuilds — Flutter can skip rebuilding it entirely because it knows the instance can never change.
How do you optimize long lists in Flutter?
Use `ListView.builder` (or `SliverList`) instead of building all items eagerly, always provide `key`s for items that can reorder, and avoid expensive work inside the `itemBuilder`.