Alexander
Alexander

Reputation: 387

Flutter Provider: proper way to split notifying

I'm trying to split firing update of widgets with Provider. I'm using latest Flutter version. Within app I'm also using context.select(), context.watch() and context.read().

Now to the main goal. What exactly I'm talking about. So I have some notifier:

class ExpenseNotifier with ChangeNotifier {
  List<Category> _selectedCategories = [];
  Expense _currentExpense;
  int _removeId;
  Expense _editExpense;
}

Now, ExpenseNotifier has a few consumers. All consumers will be updated when something will change. Except one case: when _editExpense updated only one consumer should be updated. Thing is that the class Expense already exists in the notifier, so all consumers connected to _currentExpense also reacts on _editExpense update...

I'm now using selectors. Like this:

context.select<ExpenseNotifier, Expense>((notifier) => notifier.currentExpense);

But looks like widget also reacts on _editExpense updates for some reason...

What is the proper solution for that situation? Is it possible (without defining new type) achieve it within ExpenseNotifier?

Probably, something like this should work:

class EditExpense {
  final Expense expense;
  EditExpense(this.expense);
}

So in this case wrapper class is needed. Correct me if I'm wrong

Upvotes: 0

Views: 753

Answers (1)

Anurag Tripathi
Anurag Tripathi

Reputation: 785

I found your question interesting , so I thought it would be worth working on it . I am giving a sort of general answer but I think you will be benefited from it.

First add methods to data class which will update only the required fields , like this :

class DataClass with ChangeNotifier {
  String firstString = " ";
  String secondString = " ";

  void updateFirst(String newString) {
    firstString = newString;
    notifyListeners();
  }

  void updateSecond(String newString) {
    secondString = newString;
    notifyListeners();
  }
}


Now it's time to refactor , you have to make two classes(or methods) that will have their own build methods (you can also define two methods and pass the BuildContext to them):

class StringOne extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("StringOne build method is called");
    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Column(
          children: [
            Text(context.select((DataClass value) => value.firstString)),
            Container(
              height: 100,
              width: 100,
              child: TextField(
                onChanged: (text) {
                  context.read<DataClass>().updateFirst(text);
                },
              ),
            )
          ],
        )
      ],
    );
  }
}

And

class StringTwo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("StringTwo build method is called");
    return Column(
      children: <Widget>[
        Column(
          children: [
            Text(context.select((DataClass value) => value.secondString)),
            Container(
              height: 100,
              width: 100,
              child: TextField(
                onChanged: (text) {
                  context.read<DataClass>().updateSecond(text);
                },
              ),
            ),
          ],
        )
      ],
    );
  }
}

Finally have these classes in other class which describes the UI:

class ProviderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [StringOne(), StringTwo()],
    );
  }
}

you might say it will increase verbosity , actually , refactoring often makes the code more verbose but it also makes code clearer and easy to maintain. In your case it will also prevent unnecessary builds.

Console :

I/flutter ( 1469): StringTwo build method is called
I/flutter ( 1469): StringTwo build method is called
I/flutter ( 1469): StringTwo build method is called
I/flutter ( 1469): StringTwo build method is called
I/zygote64( 1469): Increasing code cache capacity to 1024KB
I/flutter ( 1469): StringOne build method is called
I/chatty  ( 1469): uid=10140(com.example.stack_overflow) 1.ui identical 7 lines
I/flutter ( 1469): StringOne build method is called
I/flutter ( 1469): StringOne build method is called


Upvotes: 1

Related Questions