What is the fancy way to use SnackBar in StreamBuilder?
First, you must ensure that you are always returning a widget
and then you can schedule the SnackBar
for the end of the frame
if(state is AuthUnauthenticated){
WidgetsBinding.instance.addPostFrameCallback((_) => _showErrorMessage(state.errorMessage));
return Container();
}
You should also check if the data
is null o the snapshot
has data.
baeharam
Updated on December 08, 2022Comments
-
baeharam over 1 year
I'm implementing Bloc pattern for my application and I have to show SnackBar which shows error message when login is unauthenticated.
But I cannot show SnackBar during building phase of widget. I looked for lots of solutions, but I couldn't found.
What is the most efficient way to use this function?
My code
import 'package:chat_app/auth/auth_bloc.dart'; import 'package:chat_app/auth/auth_state.dart'; import 'package:chat_app/main_page.dart'; import 'package:flutter/material.dart'; void main() => runApp(App()); class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Chat App', home: MyApp(), debugShowCheckedModeBanner: false, ); } } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final AuthBloc _bloc = AuthBloc(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); @override void dispose() { _emailController.dispose(); _passwordController.dispose(); _bloc.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, appBar: AppBar(title: Text('Chat Example')), body: StreamBuilder( initialData: AuthInitializing(), stream: _bloc.authStream, builder: (BuildContext context, AsyncSnapshot<AuthState> snapshot){ AuthState state = snapshot.data; if(state is AuthUnauthenticated){ _showErrorMessage(state.errorMessage); } if(state is AuthAuthenticated){ _moveNextPage(context); } return Form( key: _formKey, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Column( children: <Widget>[ TextFormField( controller: _emailController, keyboardType: TextInputType.emailAddress, decoration: InputDecoration( border: OutlineInputBorder(), labelText: '이메일', ), ), SizedBox(height: 20.0), TextFormField( controller: _passwordController, keyboardType: TextInputType.text, obscureText: true, decoration: InputDecoration( border: OutlineInputBorder(), labelText: '비밀번호' ), ), SizedBox(height: 20.0), RaisedButton( child: Text('로그인',style: TextStyle(color: Colors.white),), onPressed: () => _bloc.addLoginData(_emailController.text, _passwordController.text), color: Theme.of(context).primaryColor, ), SizedBox(height: 15.0), state is AuthLoading ? _progressBar() : Container() ], ), ), ); }, ), ); } void _showErrorMessage(String message){ _scaffoldKey.currentState.showSnackBar(SnackBar( content: Text(message), )); } void _moveNextPage(BuildContext context) { Navigator.pushReplacement(context, MaterialPageRoute( builder: (_) => MainPage() )); } Widget _progressBar() { return Center( child: CircularProgressIndicator(), ); } }
StackTrace
I/flutter (30505): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter (30505): The following assertion was thrown building StreamBuilder(dirty, state: I/flutter (30505): _StreamBuilderBaseState>#bd8b2): I/flutter (30505): setState() or markNeedsBuild() called during build. I/flutter (30505): This Scaffold widget cannot be marked as needing to build because the framework is already in the I/flutter (30505): process of building widgets. A widget can be marked as needing to be built during the build phase I/flutter (30505): only if one of its ancestors is currently building. This exception is allowed because the framework I/flutter (30505): builds parent widgets before children, which means a dirty descendant will always be built. I/flutter (30505): Otherwise, the framework might not visit this widget during this build phase. I/flutter (30505): The widget on which setState() or markNeedsBuild() was called was: I/flutter (30505):
Scaffold-[LabeledGlobalKey#5bdc5](state: ScaffoldState#61be4(tickers: tracking 2 I/flutter (30505): tickers)) -
baeharam over 5 yearsGreat answer! Thanks