Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tried to listen to a value exposed with provider, from outside of the widget tree

Tags:

flutter

dart

So, I have a project in flutter and I'm trying to build a list of Cards where the contents depends on my OrderModel class and I'm trying to use Provider to achieve this, but I get this error:

════════ Exception caught by scheduler library ══════════════════════════

Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called Provider.of without passing listen: false.

To fix, write: Provider.of(context, listen: false);

It is unsupported because may pointlessly rebuild the widget associated to the event handler, when the widget tree doesn't care about the value. 'package:provider/src/provider.dart': Failed assertion: line 193 pos 7: 'context.owner.debugBuilding || listen == false || _debugIsInInheritedProviderUpdate'

When the exception was thrown, this was the stack

#2 Provider.of package:provider/src/provider.dart:193

#3 _OrderHistoryState._onAfterBuild package:shinier_store/screens/order_history.dart:60

#4 _OrderHistoryState.build. package:shinier_store/screens/order_history.dart:67

#5 SchedulerBinding._invokeFrameCallback package:flutter/…/scheduler/binding.dart:1102

#6 SchedulerBinding.handleDrawFrame package:flutter/…/scheduler/binding.dart:1049 ...

═════════════════════════════════════════════════════════ Stacktrace for the Provider call at _onAfterBuild()

I/flutter ( 3092): #0      _AssertionError._doThrowNew  (dart:core-patch/errors_patch.dart:42:39)
I/flutter ( 3092): #1      _AssertionError._throwNew  (dart:core-patch/errors_patch.dart:38:5)
I/flutter ( 3092): #2      Provider.of package:provider/src/provider.dart:193
I/flutter ( 3092): #3      _OrderHistoryState._onAfterBuild package:shinier_store/screens/order_history.dart:61
I/flutter ( 3092): #4      _OrderHistoryState.build.<anonymous closure> 
package:shinier_store/screens/order_history.dart:71
I/flutter ( 3092): #5      SchedulerBinding._invokeFrameCallback 
package:flutter/…/scheduler/binding.dart:1102
I/flutter ( 3092): #6      SchedulerBinding.handleDrawFrame 
package:flutter/…/scheduler/binding.dart:1049
I/flutter ( 3092): #7      SchedulerBinding._handleDrawFrame 
package:flutter/…/scheduler/binding.dart:957
I/flutter ( 3092): #8      _rootRun  (dart:async/zone.dart:1126:13)
I/flutter ( 3092): #9      _CustomZone.run  (dart:async/zone.dart:1023:19)
I/flutter ( 3092): #10     _CustomZone.runGuarded  (dart:async/zone.dart:925:7)
I/flutter ( 3092): #11     _invoke  (dart:ui/hooks.dart:259:10)
I/flutter ( 3092): #12     _drawFrame  (dart:ui/hooks.dart:217:3)

I don't know how can I possibly solve it since I added the listen:false to my Provider call. I tried using WidgetBinding, cause I thought the Provider call should be made after build is done but that didn't seem to solve the problem.

Here are the codes:

OrderModel class

class OrderModel extends ChangeNotifier {
  List<Order> myOrders;
  bool isLoading = true;
  String errMsg;
  int page = 1;
  bool endPage = false;

  void getMyOrder({UserModel userModel}) async {
    try {
      isLoading = true;
      notifyListeners();
      myOrders = await WooCommerce().getMyOrders(userModel: userModel, page: 1);
      page = 1;
      errMsg = null;
      isLoading = false;
      endPage = false;
      notifyListeners();
    } catch (err) {
      errMsg =
          "There is an issue with the app during request the data, please contact admin for fixing the issues " +
              err.toString();
      isLoading = false;
      notifyListeners();
    }
  }

  void loadMore({UserModel userModel}) async {
    try {
      isLoading = true;
      page = page + 1;
      notifyListeners();
      var orders =
          await WooCommerce().getMyOrders(userModel: userModel, page: page);
      myOrders = [...myOrders, ...orders];
      if (orders.length == 0) endPage = true;
      errMsg = null;
      isLoading = false;
      notifyListeners();
    } catch (err) {
      errMsg =
          "There is an issue with the app during request the data, please contact admin for fixing the issues " +
              err.toString();
      isLoading = false;
      notifyListeners();
    }
  }
}

order_history.dart - state class

class _OrderHistoryState extends State<OrderHistory> {
  void _onAfterBuild(BuildContext context){
     Provider.of<OrderModel>(context, listen: false)
        .getMyOrder(userModel: Provider.of<UserModel>(context));
  }

  @override
  Widget build(BuildContext context) {
    var formatter = DateFormat('dd-MM-yyyy');
    var model = Provider.of<OrderModel>(context);
    WidgetsBinding.instance.addPostFrameCallback((_) => _onAfterBuild(context));

    return Scaffold(
      appBar: AppBar(
          title: Text(
            'Order History',
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          elevation: 0.0),
      body: model.myOrders == null ? Center() :
      Padding(
        padding: const EdgeInsets.all(10.0),
        child: ListView.separated(
          separatorBuilder: (_, __) => SizedBox(height: 10.0),
          itemCount: model.myOrders.length,
          itemBuilder: (context, index) {
            String stat = model.myOrders[index].status;
            return Card(
              color: _buildColor(stat),
              elevation: 3.5,
              ...
  }
}

main.dart - build method

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => UserModel()),
        ChangeNotifierProvider(create: (_) => CartModel()),
        ChangeNotifierProvider(create: (_) => SearchModel()),
        ChangeNotifierProvider(create: (_) => OrderModel()),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primaryColor: Colors.white,
          backgroundColor: Colors.white,
          canvasColor: Colors.white,
        ),
        home: MainTabs(),
        debugShowCheckedModeBanner: false,
        localizationsDelegates: [
          i18n,
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
        ],
        supportedLocales: i18n.supportedLocales,
      ),
    );
  }
like image 792
Victor Roberti Camolesi Avatar asked Feb 05 '20 20:02

Victor Roberti Camolesi


4 Answers

I too got similar error and found out that in the newer version of Provider Package (I am using provider: ^6.0.1) you have to pass listen: false whereever you are updating the provider data.

For example on a Tap of button or any Widgets onChanged Event. Below is an example with TextField onChanged callback.

TextField(
  onChanged: (newText) {
    Provider.of<Data>(context, listen: false).changeString(newText);
  },
);
like image 158
Deeps Avatar answered Oct 19 '22 15:10

Deeps


The error seems to point out to these two lines of code to be causing the issue.

#3 _OrderHistoryState._onAfterBuild package:shinier_store/screens/order_history.dart:60

#4 _OrderHistoryState.build. package:shinier_store/screens/order_history.dart:67

The repro you've provided is incomplete and I can only guess the required flag listen: false has been added on _onAfterBuild(). However, the error logs points that var model = Provider.of<OrderModel>(context); inside Widget build() needs to also have the flag. The reason for this flag requirement is explained in the docs.

If you're still having issues, a working minimal repro will be helpful for us to understand why this behavior occurs.

like image 29
Omatt Avatar answered Oct 19 '22 14:10

Omatt


If you use provider version ^6.0.2, use:

context.read<TaskData>().addMyTask(
          Task(
            name: newTaskTitle,
          ),
        );

Instead of this:

context.watch<TaskData>().addMyTask(
          Task(
            name: newTaskTitle,
          ),
        );
like image 2
Berkay Başöz Avatar answered Oct 19 '22 14:10

Berkay Başöz


If you are using provider ^6.0.2 then use:

context.read<YourFunction>()

not:

context.watch<YourFunction>()
like image 2
Lance Olana Avatar answered Oct 19 '22 15:10

Lance Olana