0

According to Flutter's documentation here (https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple),

one way to control the state management is to use ChangeNotifierProvider(or InheritedWidget) when one of its descendants is a Consumer which is rebuilt when the underlying ChangeNotifier changes. Flutter's team reiterates that approach on the official youtube Flutter channel.

However, that means that some business logic element (ChangeNotifier) is now part of the Widget tree (which otherwise is all about how the UI will look like). So I don't understand why those classes (ChangeNotifierProvider,InheritedWidget,Consumer) even exist.

In particular, why isn't the following approach superior:

-Business logic is a singleton and a ChangeNotifier.

-Instead of Provider(...), for every Widget depending on the business logic simply do this:

BusinessLogicSingleton.instance.addListener(() {

      setState(() {

      });

at initState(...).

What am I missing here?

yoni keren
  • 300
  • 2
  • 14

4 Answers4

0

You can indeed do that, but then you'd also have to remember to close the listener on dispose. Providers handle that automatically.

Randal Schwartz
  • 39,428
  • 4
  • 43
  • 70
  • Interesting point. Since that code would look the same for all those Widgets (initState and dispose), if the Flutter team will add support for that (because forgetting to not listen at dispose will suck to debug), how would the approach be inferior at that point? – yoni keren Oct 24 '21 at 20:19
  • Dart doesn't provide destructor callbacks. So the dispose and close stuff must be handled by user code at the appropriate points. – Randal Schwartz Oct 25 '21 at 00:01
0

How do you plan to set state in stateless widgets? Also following your suggested method, you would be rebuilding the entire widget with setstate, vs building only a specific part even for complex widgets if you were to use consumers.

Huthaifa Muayyad
  • 11,321
  • 3
  • 17
  • 49
  • Your points could be valid, but to make everything clear I'll share why I still don't completely understand: 1. By definition, the Widget depending on the data at the ChangeNotifier depends on some state of our business logic... therefore, making it stateful is logical IMHO. 2. You can literally break the bigger Widget into smaller parts, it's exactly the same as suggested with the Consumer, which you can misuse in exactly the same way. – yoni keren Oct 24 '21 at 20:15
  • Review my answer if you can - You can use this widget in stateless widget, and in the midst of any widget, so that you don't have to rebuild the entire thing. – yoni keren Dec 28 '21 at 22:28
0

I think there are benefits to have the ChangeNotifier a part of the widget tree. You need to ask yourself: what are the features of the Widget Tree that can benefit ChangeNotifier? Or rather - by using Widget Tree, can I get everything I get from Singleton? And can I do some things Singleton does not provide?

First - if you put your ChangeNotifier high in the tree, and you create only one ChangeNotifier for your class (e.g. ChangeNotifier) - you practically have a singleton. With added benefit of a Widget Tree logic taking care of disposing your ChangeNotifier etc.

Second - you can have multiple ChangeNotifiers of the same class in different parts of the tree, practically scoping your ChangeNotifier any way you want. This is not something a Singleton approach can offer. I'm not sure this is a good example - but imagine your ShoppingCart demo: it has a single ShoppingCart ChangeNotifier provider at the top of the tree. Now imagine one of the items you sell are customizable - like Pizza. And when user selects Pizza - you open additional screen where a user will chose toppings. Now, this additional screen could have a new instance of ShoppingCart - tracking the toppings you added, with all the features of the shopping cart - add, remove etc. This way your module (Pizza toppings selection) becomes self-contained - it does not expect a Singleton to be provided for it, but it will inject it's own ChangeNotifier into the tree. With the Singleton approach you would need to come up with another way - extending your shopping cart for the sake of creating another Singleton. Not very practical.

Andrija
  • 1,534
  • 3
  • 10
0

Following up on the question, the following hyper-simple class saves me a lot of boilerplate code, and illogical code (forcing ChangeNotifier to be a part of the Widget tree via Provider etc)

import 'package:flutter/material.dart';

//A class which makes it easier to worker with change notifier without provider/consumer which looks wrong since changenotifier shouldn't be forced into widgets tree for no reason
//eg widgets should represent UI and not business logic


class ListenerWidget extends StatefulWidget {
  const ListenerWidget({Key? key,required ChangeNotifier notifier,required Widget Function(BuildContext) builder,void Function()? action}) : notifier=notifier,builder=builder,action=action,super(key: key);
  final Widget Function(BuildContext) builder;
  final ChangeNotifier notifier;
  final void Function()? action;

  @override
  _ListenerWidgetState createState() => _ListenerWidgetState();
}

class _ListenerWidgetState extends State<ListenerWidget> {

  void emptyListener(){
    setState(() {

    });
  }

  @override
  void initState() {
    widget.notifier.addListener(widget.action??emptyListener);
    super.initState();
  }

  @override
  void dispose() {
    widget.notifier.removeListener(widget.action??emptyListener);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.builder(context);
  }
}
yoni keren
  • 300
  • 2
  • 14