I am watching a simple StreamProvider
which just emits an int value. MyWidget
is building only once if I am not assigning anything to theme
variable but if I assign anything to theme
then widget builds around 12 times.
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final provider = ref.watch(streamProvider);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
textButtonTheme: TextButtonThemeData(
style: OutlinedButton.styleFrom(foregroundColor: Colors.red),
),
),
home: const MyWidget(),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
print("@@@@ build MyWidget");
return Container(
color: Theme.of(context).primaryColor,
);
}
}
final streamProvider = StreamProvider.autoDispose(((ref) => Stream.value(1)));
This is printing @@@@ build MyWidget
12 times. If I do not read anything from Theme.of
then it prints only once. What could be the issue here?
Edit
Everyone is saying it is the problem with Theme.of(context)
but my confusion is why it is building only once if I convert ref.watch
to ref.read
?
6
Answers
This is because of using
StreamProvider.autoDispose
which triggers the rebuilds in widgets that are using the stream.You can use
StreamProvider
without.autoDispose
which will only rebuild the widget that is listening to the stream changes.As far as I can tell, this is not about Riverpod. You can remove any Riverpod dependencies and the problem will remain.
Also, I’ve narrowed down the problem a bit. Take a look at this code:
The problem appears whenever we define a new style in the line:
style: TextButton.styleFrom(elevation: 1),
If we write
TextButton.styleFrom()
, everything works as expected. Also, if we don’t useTheme.of(context)
, that’s fine too.It is probably necessary to open issue 🙂
It is combination of many things.
Every time a event is emitted, there are other widgets (part of build function of MaterialApp which gets rebuilt. AnimatedTheme, AnimatedTheme and MyWidget were marked dirty by framework in this case. You can verify it yourself by adding
print('marking $this as dirty');
to flutter’s framework.dart markNeedBuild method’s end.I think there is nothing wrong with either riverpod or flutter.
Have you considered the use of ref.listen instead of ref.watch? with ‘listen’ you can compare the new emitted value with the old, and SetState only if there is a change…
may stream is being re created or you try to assign value multiple times
sure you can try