Matt
Matt

Reputation: 803

Flutter Riverpod: Using ref.watch Outside of Build Function

In my Flutter app, I have a function gotoPage() that animates a PageView widget to a new page. I'd like this function to be called whenever newPageProvider is updated. How do I "activate" the ref.watch() inside the function gotoPage() when gotoPage() is not part of build() function?

providers.dart

final newPageProvider = StateProvider<int>((ref) => 0);

widget.dart

class _WidgetState extends ConsumerState<WidgetState> {

  final pageController = PageController(
    initialPage: 0,
  );

  @override
  Widget build(BuildContext context) {
    return PageView.builder(
      controller: pageController,
      itemCount: data.length,
      itemBuilder: (context, index) {
        return WidgetCard(poi: data[index], itemIndex: index);
      },
    );
  }

  void gotoPage() {
    final index = ref.watch(newPageProvider);
    pageController.animateToPage(
      index,
    );
  }

}

Upvotes: 5

Views: 6616

Answers (2)

Josteve Adekanbi
Josteve Adekanbi

Reputation: 12673

EDIT: Use ref.listen in build() instead.

Like so:

@override
Widget build(BuildContext context){
 ref.listen(
   newPageProvider,
   (oldIndex, newIndex){
     pageController.animateToPage(newIndex);
   }
 );
 return Scaffold(...);
}

Upvotes: 2

Matt
Matt

Reputation: 803

I believe the answer is use ref.listen, not ref.watch (as shown below).

From the RiverPod user guide:

Similarly to ref.watch, it is possible to use ref.listen to observe a provider.

The main difference between them is that, rather than rebuilding the widget/provider if the listened provider changes, using ref.listen will instead call a custom function.

The listen method should not be called asynchronously, like inside onPressed or an ElevatedButton. Nor should it be used inside initState and other State life-cycles.

providers.dart

final newPageProvider = StateProvider<int>((ref) => 0);

widget.dart

class _WidgetState extends ConsumerState<WidgetState> {

  final pageController = PageController(
    initialPage: 0,
  );

  @override
  Widget build(BuildContext context) {
    ref.listen<int>(newPageProvider, (int previousIndex, int newIndex) {
      _gotoPage(newIndex);
    });
    return PageView.builder(
      controller: pageController,
      itemCount: data.length,
      itemBuilder: (context, index) {
        return WidgetCard(poi: data[index], itemIndex: index);
      },
    );
  }

  void gotoPage(index) {
    pageController.animateToPage(
      index,
    );
  }

}

Upvotes: 5

Related Questions