listenable_widget 0.1.0 copy "listenable_widget: ^0.1.0" to clipboard
listenable_widget: ^0.1.0 copied to clipboard

A widget that listens to a ChangeNotifier and rebuilds when it changes.

ListenableWidget #

A conviniënt widget that helps you separate UI from Logic, using ChangeNotifiers.

Goal #

The aim for this package is provide a simple way of separating UI from Logic while maintaining the simplicity of StatefulWidget.

In general, a StatefulWidget is structured with both the Widget and the State in the same file. The function that builds the UI is located inside the State.

ListenableWidget 'fixes' this by having you to override a build method which passes the ViewModel.

Usage #

This package is designed to fullfill the VVM of MVVM, where the ListenableWidget is the View and the ChangeNotifier serves as the ViewModel.

A typical implementation will exist of two parts:

ViewModel #

We start with creating our ViewModel which must be a ChangeNotifier. Whenever we call notifyListeners() on our ViewModel, the ListenableWidget will rebuild.

class CounterViewModel with ChangeNotifier {
    // While it's not required, using the private + public getter combo
    // prevents consumers from accidently circumventing any notifyListeners.
    int _count = 0;
    int get count => _count;

    void increment() {
        _count++;
        notifyListeners();
    }
}

View #

Next we can create our View. We do this by extending ListenableWidget and override at least the two required methods, create and build:

class CounterView extends ListenableWidget<CounterViewModel> {

    @override
    CounterViewModel create(context) {
        return CounterViewModel();
    }

    @override
    void build(context, viewModel) {
        return Scaffold(
            // imagine beautiful UI here
            Text(viewModel.count)
            // imagine beautiful UI here
            IncrementButton( onPressed: viewModel.increment),
            // imagine beautiful UI here
        );
    }
}

Methods overview #

The ListenableWidget has three methods of which two are required.

create (required) #

Whenever you extend ListenableWidget, you must override create to provide a ViewModel. This will only be called once, when the Widget is created.

Often you will use this to create a new instance of the ViewModel but it's also possible to provide an already existing ViewModel, like when you want to share state between pages.

// Example of creating a new instance
@override
MyViewModel create(BuildContext context) {
    return MyViewModel(initialValue);
}

// Example of getting an existing ViewModel using Provider
@override
MyViewModel create(BuildContext context) {
    return context.read<MyViewModel>();
}

build (required) #

The other required method to override is build. The build method should return your UI. It works similar to the build method you're used to from StatelessWidget and StatefulWidget, but has one extra argument which is the ViewModel.

The build method will be called every time notifyListeners() is called on the ViewModel.

@override
Widget build(context, viewModel) {
    return MyWidget(
        onTap: viewModel.doSomething,
        value: viewModel.currentValue,
    );
}

update (optional) #

The update method is called whenever the Widget is updated. Because the ViewModel only gets created once, you can use update to update the ViewModel. This is useful when your Widget has fields that can be update by its parent and which should be reflected in the ViewModel.

class CounterWidget extends ListenableWidget<CounterViewModel> {
    // The parent passes a counterMode
    CounterWidget(this.counterMode);

    final CounterMode counterMode; 

    @override
    CounterViewModel create(context) {
        // When the Widget is first created, it will use
        // the counterMode during creation.
        return CounterViewModel(initialCounterMode: counterMode);
    }

    @override
    void update(context, oldWidget, viewModel) {
        // When the widget is updated by the parent, this is called.
        // We then check if the counterMode has changed, if so,
        // we update it on the ViewModel.
        if(oldWidget.counterMode != counterMode) {
            viewModel.updateCounterMode(counterMode);
        }
    }

    @override
    Widget build(context, viewModel) {
        // UI
    }
}

Disposing #

By default, ListenableWidget will call dispose on the ViewModel when the Widget is disposed so you can clean-up. This should be fine in most cases.

If you have a Widget that does not create an instance of the ViewModel, but get's it from somewhere else, this most likely means that you don't want your Widget to dispose the ViewModel either.

In this case you can simply override the autoDispose property on your widget to return false.

@override
final autoDispose = false;

Additional information #

This package is aimes for simplicity and that's why you don't find certain things you might find in other state management libraries.

If you wish to optimize rebuilds, it's up to you to do so by calling notifyListeners() strategically.

In general, you'd want ListenableWidget to instantiate it's own ViewModel. For more complex scenarios where you wish to share ViewModels you will have to manage that yourself, for example by using Provider.

This package has ironically been born from the desire to not use a package for state management. So if you don't want to rely on a package either, you can also just copy listenable_widget.dart into your project.

4
likes
160
points
132
downloads

Publisher

verified publisherveenstra.dev

Weekly Downloads

A widget that listens to a ChangeNotifier and rebuilds when it changes.

Homepage
Repository (GitHub)

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on listenable_widget