Describe the bug
I find the BlocBuilder is called twice when App is navigated to another screen and back. I think the BlocBuilder shouldn't be called during the navigation because BlocState doesn't change during the navigation.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
I think the BlocBuilder shouldn't be called during the navigation.
*Logs *
Performing hot restart...
Restarted application in 1,325ms.
flutter: Out BlocBuilder
flutter: In BlocBuilder
flutter: In BlocBuilder
flutter: In BlocBuilder
import 'package:flutter/material.dart';
import 'package:equatable/equatable.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() => runApp(BlocProvider<SomeBloc>(
builder: (context) => SomeBloc(),
child: MyApp(),
));
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/': (context) => HomePage(),
'/another': (context) => AnotherPage(),
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home Page')),
body: Center(
child: Column(
children: [
() {
print('Out BlocBuilder');
return Container();
}(),
BlocBuilder<SomeBloc, SomeState>(builder: (context, state) {
print('In BlocBuilder');
return Container();
}),
RaisedButton(
child: Text('Go another page'),
onPressed: () {
Navigator.of(context).pushNamed('/another');
},
),
],
),
),
);
}
}
class AnotherPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Another Page')),
body: Center(
child: Text('Another Page'),
),
);
}
}
class SomeEvent extends Equatable {
const SomeEvent();
@override
List<Object> get props => [];
}
class SomeState extends Equatable {
const SomeState();
@override
List<Object> get props => [];
}
class SomeBloc extends Bloc<SomeEvent, SomeState> {
@override
SomeState get initialState => SomeState();
@override
Stream<SomeState> mapEventToState(
SomeEvent event,
) async* {
// TODO: Add Logic
}
}
Hi @marklureal 馃憢
Thanks for opening an issue!
This is expected behavior and BlocBuilder can be built many times by Flutter itself. As a result, you need to make sure your builder is a pure function (no side-effects) and should assume it can be called 60 times per second (on every frame).
StreamBuilder behaves the same way:
import 'package:flutter/material.dart';
import 'package:equatable/equatable.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() => runApp(BlocProvider<SomeBloc>(
builder: (context) => SomeBloc(),
child: MyApp(),
));
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/': (context) => HomePage(),
'/another': (context) => AnotherPage(),
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('HomePage build');
return Scaffold(
appBar: AppBar(title: Text('Home Page')),
body: Center(
child: Column(
children: [
StreamBuilder(
initialData: null,
stream: BlocProvider.of<SomeBloc>(context),
builder: (context, state) {
print('In StreamBuilder');
return Container();
},
),
BlocBuilder<SomeBloc, SomeState>(
builder: (context, state) {
print('In BlocBuilder');
return Container();
},
),
RaisedButton(
child: Text('Go another page'),
onPressed: () {
Navigator.of(context).pushNamed('/another');
},
),
],
),
),
);
}
}
class AnotherPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Another Page')),
body: Center(
child: Text('Another Page'),
),
);
}
}
class SomeEvent extends Equatable {
const SomeEvent();
@override
List<Object> get props => [];
}
class SomeState extends Equatable {
const SomeState();
@override
List<Object> get props => [];
}
class SomeBloc extends Bloc<SomeEvent, SomeState> {
@override
SomeState get initialState => SomeState();
@override
Stream<SomeState> mapEventToState(
SomeEvent event,
) async* {
// TODO: Add Logic
}
}
Hope that helps 馃憤
Thanks very much :)
Most helpful comment
Thanks very much :)