'Prevent repeated API calls upon Changing Screens in Flutter
I was looking for alternatives in which the data is loaded from API only once and stays that way if I move to and fro that screen and I found one in using InheritedWidget. However, I'm now getting the below error and I cannot figure out how to get rid of this.
The getter 'users' was called on null.
Receiver: null
Tried calling: users
The errors are marked as comments in the below:
My code:
InheritedWidget Class
class InheritedUsers extends InheritedWidget {
final UsersList users;
InheritedUsers({required Key key, required Widget child})
: assert(child != null),
users = UsersList(),
super(key: key, child: child);
static UsersList of(BuildContext context) =>
(context.dependOnInheritedWidgetOfExactType(aspect: InheritedUsers)
as InheritedUsers)
.users;
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
}
class UsersList {
late List<User> listOfUsers;
Future<List<User>> get userList async {
return listOfUsers = await UsersApi.getUsers();
}
}
class UsersApi with ChangeNotifier {
static Future<List<User>> getUsers() async {
// List<User> list = [];
// late final body;
final url =
'https://firebasestorage.googleapis.com/v0/b/web-johannesmilke.appspot.com/o/other%2Fvideo126%2Fusers.json?alt=media';
final response = await http.get(Uri.parse(url));
final body = json.decode(response.body);
return body.map<User>(User.fromJson).toList();
}
}
UserNetworkPage widget
class UserNetworkPage extends StatefulWidget {
UserNetworkPageState createState() => UserNetworkPageState();
}
class UserNetworkPageState extends State<UserNetworkPage> {
late final Future<List<User>> result;
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
result = InheritedUsers.of(context).userList; //This is where the error gets thrown
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) => Scaffold(
body: FutureBuilder<List<User>>(
future: result,
builder: (context, snapshot) {
final users = snapshot.data;
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return Center(child: Text('Some error occurred!'));
} else {
return buildUsers(users!);
}
}
},
),
);
Widget buildUsers(List<User> users) => ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => UserPage(user),
)),
leading: CircleAvatar(
backgroundImage: NetworkImage(user.urlAvatar),
),
title: Text(user.username),
subtitle: Text(user.email),
);
},
);
}
Solution 1:[1]
What you need at this point is a state management solution. There's a lot of them, and I'm pretty sure they all use InheritedWidget underneath.
Introduction to state management
List of state management approaches
I personally recommend Riverpod, Provider or BLoC.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | MickaelHrndz |
