I have a stateful widget called AuthenticatingScreen
where I’m trying to perform the following flow…
- Output message letting the user know we are logging them in
- Get user oAuth token (calls to service file)
- Update the message to let the user know we are loading their details
- Fetch the users details and redirect them away
The problem is that at step three, I’m rebuilding the state, which is in turn causing the build
method to be fired again and calling the service again, which triggers an exception.
import 'package:flutter/material.dart';
import 'package:testing/services/auth_service.dart';
class AuthenticatingScreen extends StatefulWidget {
final String token;
AuthenticatingScreen(this.token);
@override
State<AuthenticatingScreen> createState() => _AuthenticatingScreenState();
}
class _AuthenticatingScreenState extends State<AuthenticatingScreen> {
// step 1) our default message
String _message = 'Please wait while we log you in...';
Future<void> _fetchUserDetails() {
return Future.delayed(const Duration(seconds: 3), () {
// ToDo: fetch user details from the server
});
}
@override
Widget build(BuildContext context) {
// step 2) get our oAuth token
AuthService.handleCallback(widget.token).then((accessCode) async {
// step 3) update our message
setState(() => _message = 'We're just getting your details');
// step 4) retrieve our user details and redirect away
_fetchUserDetails().then((_) {
Navigator.of(context).pushNamedAndRemoveUntil(
'/home',
(Route<dynamic> route) => false,
);
});
});
/// output our authenticating screen.
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.only(bottom: 20.0),
child: CircularProgressIndicator(),
),
Text(_message),
],
),
),
);
}
}
My question being: How can I work around this / extract this logic to only fire when the widget is created, while still having access to the build context for navigation?
I’ve tried making the widget itself stateless and extracting the message and spinner into a separate widget, but changing the input argument alone still doesn’t force a rebuild.
2
Answers
Ok, so I have figured out the solution. It seems making service calls within the
build()
method is a bad idea.Moving my service calls into a void function which can then be called within the
initState()
method seems to be the way to go.And this way when the
build()
method is called again for the rebuild, very little details have to be redrawn.you can do it this way, i usually use getx & controller to achieve this.
service class