Using same riverpod state provider for multiple pages

2,376

I finally find the answer. thanks @EdwynZN By using family keyword, I can create some thing like a family for each category

class NewsList extends StatefulWidget {
  Category category;

  NewsList({this.category});

  @override
  State<StatefulWidget> createState() {
    return _NewsListState(category:category);
  }
}


class _NewsListState extends State<NewsList> with AutomaticKeepAliveClientMixin<NewsList> {
  Category category;

  _NewsListState({this.category});
  
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
     
      // add category.id to newsProvider, instead of getNewsList()
      context.read(newsProvider(category.id)).getNewsList();
    });
  }


  @override
  Widget build(BuildContext context) {
    return Consumer(builder: (ctx, watch, child) {

      //newsProvider(category.id) just listen to specific category id and not listen to all ids
      return watch(newsProvider(category.id).state).map( 
        init: (value) {
          return Container();
        },
        loading: (value) {
          return Container(
            child: Center(
              child: CircularProgressIndicator(),
            ),
          );
        },
        success: (value) {
          return Container(child: getNewsItem(value.newsList));
        },
        serverError: (value) {
          return Container();
        },
      );
    });
  }


  @override
  bool get wantKeepAlive => true;
}

//using family here and pass <My State, Category id>
final newsProvider = StateNotifierProvider.family<NewsListNotifier, int>((ref, catID) {
  var newsService = ref.watch(newsServiceProvider);
  return NewsListNotifier(newsService, catID);
});

class NewsListNotifier extends StateNotifier<NewsListState> {
  final NewsService serviceRepository;
  int catID;

  NewsListNotifier(this.serviceRepository, this.catID) : super(NewsListState.init());


  getNewsList() async {
    state = NewsListState.loading();
    DataResponse request = await serviceRepository.getNewsList(catID, page, 20);

    request.maybeWhen(
      success: (value) {

        if (value.data != null) {
          state = NewsListState.success(newsList: value.data);
        }
      },
      error: (error) {
        state = NewsListState.serverError(error);
      },
      orElse: () {},
    );
  }

}
Share:
2,376
Erfan Eghterafi
Author by

Erfan Eghterafi

Android developer

Updated on December 26, 2022

Comments

  • Erfan Eghterafi
    Erfan Eghterafi over 1 year

    I I'm using provider for state management (actually riverpod) In my project I have a tabview and use each tab for a category and each shows news list. tabview size is not fix and I use same page for all tabs and pass category id to page.

    The problem is that newsProvider allways keep last category id and all pages show same news list. Who I can separate newsProvider list for each pages?

    //create tabview in my stateFullWidget
    @override
    Widget build(BuildContext context) {
       return Scaffold(
       body: DefaultTabController(
         length: europeanCountries.length, // europeanCountries has dynamic size
             child: new Scaffold(
                appBar: new AppBar(
                     
                flexibleSpace: new Column( 
                   children: [
                      new TabBar( 
                          tabs: europeanCountries.map<Widget>((e) => getTab(e, FontAwesomeIcons.newspaper)).toList()),
                        ],
                      ),
                    ),
    
                   // dynamically create NewsList and pass category id
                    body: TabBarView(children: europeanCountries.map((catItem) => NewsList(category: Category(title: catItem.title, id:catItem.id))).toList()),
                  ),
                )
           )
     }
    
    class NewsList extends StatefulWidget {
      Category category;
    
      NewsList({this.category});
    
      @override
      State<StatefulWidget> createState() {
        return _NewsListState(category:category);
      }
    }
    
    class _NewsListState extends State<NewsList> with AutomaticKeepAliveClientMixin<NewsList> {
      Category category;
    
      _NewsListState({this.category});
      
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          context.read(newsProvider).getNewsList(category.id);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Consumer(builder: (ctx, watch, child) {
          return watch(newsProvider.state).map(
            init: (value) {
              return Container();
            },
            loading: (value) {
              return Container(
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              );
            },
            success: (value) {
              return Container(child: getNewsItem(value.newsList));
            },
            serverError: (value) {
              return Container();
            },
          );
        });
      }
    
      @override
      bool get wantKeepAlive => true;
    }
    
    
    
    
    final newsProvider = StateNotifierProvider.autoDispose<NewsListNotifier>((ref) {
      var newsService = ref.watch(newsServiceProvider);
      return NewsListNotifier(newsService);
    });
    
    class NewsListNotifier extends StateNotifier<NewsListState> {
      final NewsService serviceRepository;
    
    
      NewsListNotifier(this.serviceRepository) : super(NewsListState.init());
    
    
      getNewsList(int catID) async {
        state = NewsListState.loading();
        DataResponse request = await serviceRepository.getNewsList(catID);
        request.maybeWhen(
          success: (value) {
    
            if (value.data != null) {
              state = NewsListState.success(newsList: value.data);
            }
          },
          error: (error) {
            state = NewsListState.serverError(error);
          },
          orElse: () {},
        );
      }
    
    }