I have learned that it brings problems when initating a future- or streambuilder inside the build of a widget since it will lead to unwanted fetching of data.
To do this you pass the stream outside of the build-method. But this leads to another problem. In my case I have to get an id-argument from the last widget but that can only be reached inside the build. I have searched the internet for explanations on how to solve this but I cant find an easy and clean explanation on the best way to do this. A good solution that initialize the future with the build outside of the build.
My material app:
MaterialApp(
routes: appRoutes,
);
My routes table:
var appRoutes = {
Screen1.routeName: (context) => Screen1(),
Screen2.routeName: (context) => Screen2(),
};
How I send the argument from screen1:
onTap: () {
Navigator.of(context).pushNamed(
Screen2.routeName,
arguments: id,
);
},
screen2: (which doesnt work this way)
class Screen2 extends StatefulWidget {
static const routeName = '/screen2';
@override
State<Screen2> createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
@override
final String id = ModalRoute.of(context)!.settings.arguments as String; <====== Impossible
final _stream = FirestoreService().getData(id);
Widget build(BuildContext context) {
return FutureBuilder<Map>(
future: _stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
print('succes');
} else {
print('Fail');
}
});
}
}
CodePudding user response:
Way1: late
keyword (unstable)
Use late
keyword for lazy initialiation of your argument, stream.
class Screen2 extends StatefulWidget {
static const routeName = '/screen2';
@override
State<Screen2> createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
@override
late final String id = ModalRoute.of(context)!.settings.arguments as String; <====== Impossible
late final _stream = FirestoreService().getData(id);
Widget build(BuildContext context) {
...
}
}
Way2: onGerateRoute
constructor (good)
You can check this answer for using onGenerateRoute
. It is more proper way.
Way3: Create extraction delegation screen (good)
In the docs, the best practice is creating a delegation screen for extract arguments.
It parse argument in build
method and pass it to new screen.
// A Widget that extracts the necessary arguments from
// the ModalRoute.
class ExtractArgumentsScreen extends StatelessWidget {
const ExtractArgumentsScreen({super.key});
static const routeName = '/extractArguments';
@override
Widget build(BuildContext context) {
// Extract the arguments from the current ModalRoute
// settings and cast them as ScreenArguments.
final args = ModalRoute.of(context)!.settings.arguments as ScreenArguments;
return Scaffold(
appBar: AppBar(
title: Text(args.title),
),
body: Center(
child: Text(args.message),
),
);
}
}