Flutter control tab programmatically via Provider

Viewed 490

I am unable to figure out how I can listen to changes in a class that uses the ChangeNotifier class. More specifically, outside the widget build method. So far I've tried simply attaching listeners to the class like so:

final providerObj = SomeProvider();

void initState() {
  providerObj.addListener(() {
     print("Something happens");
  });    
}

But this does nothing. I don't know why. I got it working once, but afterwards it just died on me. Nothing gets triggered, when there is a change in the provider class' variable values.

Here's a snippet of the SomeProvider

class SomeProvider with ChangeNotifier {
  int _tabIndex = 0;
  List<Tab> _tabs = [];
  Tab _searchTab = new Tab(id: 0, name: 'Search');

  void searchItems(String searchWord) {
    _searchTab.items.addAll(_items
        .where((item) => product.item.contains(searchWord))
        .toList());

    setTabIndex(0);
  }

  void setTabIndex(int index) {
    _tabIndex = index;
    notifyListeners();
  }

  /// Get all products
  List<Category> get tabs {
    return [..._tabs];
  }

  int get tabIndex {
    return _tabIndex;
  }

What I'm trying to accomplish is simple: Control the selected tab, when the selected index is in the SomeProvider class. Every time a tab is pressed, the index value gets saved in the provider. When the value changes, it should trigger an animateTo() call for a TabController instance.

The reason for this is because I have a separate search widget, which needs to change the tab to a Search tab. I just have no idea how I can listen to changes in the provider class outside the build() method and change the TabController index there.

So, I have a basic TabBarView to which I give a TabController instance.

class _ProductsState extends State<Products> with TickerProviderStateMixin {
  late TabController _tabController;

  void initState() {
    super.initState();

    _tabController = TabController(
      vsync: this,
      length: 0,
      initialIndex: 0,
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  
  Future<void> _fetchTabs(context) async {
    await Provider.of<SomeProvider>(context, listen: false)
        .fetchTabs();

    _tabController = TabController(
      vsync: this,
      length: Provider.of<SomeProvider>(context, listen: false)
          .tabs
          .length,
    );
  }

  Widget build(BuildContext context) {
    // There's  a FutureBuilder here etc.
    ...
    child: TabBarView(
        controller: _tabController,
        ...

What I'm trying to do is something like:

void triggeredWhenStateChanges() {
    _tabController.animateTo(Provider.of<SomeProvider>(context, listen: false).tabIndex);
}

Little bit off-topic: I've used React before (not React-Native) and with it you can use something called a hook which can perform side effects when a value change is detected. With the useEffect hook I can normally execute some actions when a value in the state changes. I don't know how I can do this with Flutter, if it can be done at all.

0 Answers
Related