i have a question
here i am fetching data from api and i made a second page that i can post from my app in api .
when i post something and i come back to the main page that there is a lit of all of the post from my api , i need a refresh ... when i refresh it the new post will be added but the refreshing circle won't stop refreshing ..
i have no idea what to do ..
one place i read it's because of set state that creates an infinitive loop .. but i my case i need the set state to update the ui .. please tell me what to do . please help me thank u .
this is my code :
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyPage(),
);
}
}
class MyPage extends StatefulWidget {
const MyPage({super.key});
@override
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
final RefreshController _myrefreshcontroller = RefreshController();
late List<Post>? listpost;
@override
void initState() {
fetchAllPosts().then((value) => listpost = value);
super.initState();
}
void _onRefresh() async {
await fetchAllPosts().then((value) {
setState(() {
listpost = value;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('welcome welcome'),
),
body: Center(
child: FutureBuilder(
future: fetchAllPosts(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return SmartRefresher(
controller: _myrefreshcontroller,
onRefresh: _onRefresh,
child: ListView.builder(
itemCount: listpost!.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
contentPadding: const EdgeInsets.all(20),
title: Padding(
padding: const EdgeInsets.all(20),
child: Text(listpost![index].id.toString())),
subtitle: Padding(
padding: const EdgeInsets.all(20),
child: Text(listpost![index].content.toString())),
),
);
},
),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return const CircularProgressIndicator();
},
),
),
The package you’re using for refreshing recommends adding _refreshController.refreshCompleted()
on a successful refresh, which your code is missing. With a bit of error handling, it should look like this:
void _onRefresh() async {
fetchAllPosts().then((value) {
setState(() {
listPost = value;
});
_refreshController.refreshCompleted();
}).catchError((error) {
_refreshController.refreshFailed();
});
}
And yes, while the setState
would cause the infinite loop if you were using Flutter’s default RefreshIndicator
, in cases where you need to trigger a rebuild in your FutureBuilder
without resetting the future, you can workaround this by making the future memoized first.
In summary, memoizing your future would change the behaviour of your FutureBuilder
to only rebuild when the future itself changes and not on every setState
call.
To do this, based on your code, the code before your _onRefresh
method would now look like this:
final RefreshController _refreshController = RefreshController();
late Future<List<Post>> futurePosts;
late List<Post>? listPost;
@override
void initState() {
super.initState();
futurePosts = fetchAllPosts();
}
and in your FutureBuilder
, you would update the future to use the memoized data, which would then look like:
FutureBuilder<List<Post>>(
future: futurePosts,
…