Introduction
Pull-to-refresh is a common UX pattern where users swipe down to reload content. In Flutter, the RefreshIndicator widget provides this functionality. When combined with GetX, you can manage the refresh state reactively, showing loading indicators and updating the data seamlessly. This guide covers how to implement pull-to-refresh with GetX controllers, including error handling and best practices.
Basic Setup
First, create a controller that holds the data and a method to fetch it. Use reactive variables to automatically update the UI when the data changes.
Implementing RefreshIndicator
In your view, wrap a ListView with RefreshIndicator. The onRefresh callback should call the controller's fetch method and return a Future. GetX automatically updates the UI when items changes.
Handling Refresh State
The onRefresh callback should return a Future. The RefreshIndicator shows its built‑in loading spinner while the future is pending. You don't need a separate loading indicator for the refresh action, but you may want to show a loading state for the initial load.
Error Handling During Refresh
If an error occurs during refresh, you should show a message to the user. You can use Get.snackbar or a reactive error variable. The RefreshIndicator will still finish (the spinner stops), so you need to handle the error separately.
Using StateMixin for Cleaner Code
You can also use StateMixin to handle loading, error, and data states in one place. Then your view can use .obx() and the onRefresh callback can simply call the fetch method that updates the mixin state.
Best Practices
- Show initial loading state – When the screen first opens, show a loading indicator if data is empty.
- Use
assignAllto update lists – Replacing the whole list with.value = newListcan be less efficient; use.assignAllto trigger reactivity properly. - Handle errors gracefully – Show a snackbar or a widget with a retry button.
- Avoid duplicate refreshes – Use a flag to prevent multiple simultaneous refresh calls, though
RefreshIndicatoralready handles that. - Keep the controller focused – One controller per data source or screen.
Common Mistakes
- ❌ Forgetting to call
refreshon the controller – TheonRefreshcallback must return aFuturethat completes when data is ready. - ❌ Not handling the case where refresh fails – The user sees the spinner disappear but no feedback. ✅ Show an error message.
- ❌ Using
Obxincorrectly insideRefreshIndicator– ThechildofRefreshIndicatormust be a scrollable widget; usingObxthat returns aListViewis fine. - ❌ Setting
isLoadingto true inside refresh – This will show an extra loading indicator over the refresh spinner, causing visual duplication. ✅ Only useisLoadingfor initial load or for operations not triggered by refresh.
FAQ
- Q: Can I use
RefreshIndicatorwith aCustomScrollView?
A: Yes, as long as thechildis a scrollable widget. Wrap theCustomScrollViewwithRefreshIndicator. - Q: How do I add a pull-to-refresh to a
GridView?
A: Same approach – wrap theGridViewwithRefreshIndicator. - Q: Does
RefreshIndicatorwork on the web?
A: Yes, with mouse drag it works similarly. - Q: How to combine refresh with pagination?
A: In your controller, have separate methods for initial load and load more. For refresh, reset the page and fetch from scratch. - Q: Can I use
GetBuilderinstead ofObx?
A: Yes, butObxis more concise. If you need fine‑grained control, you can useGetBuilderwithupdate().
Conclusion
Implementing pull-to-refresh with GetX is straightforward: combine RefreshIndicator with a controller that holds your data and a fetch method. By using reactive state, you ensure the UI updates automatically when data changes. With the added patterns like StateMixin, you can also handle loading and error states elegantly.