Getting started to Flutter Provider
Tags: flutter, provider, mobile, dart
Published: 2023-04-03 05:04:28

## What is Provider?
Provider is one of the many state management options when using Flutter. It’s one of the first state manager recommended by Flutter itself and one of the simplest. If you’re new to state management check out the official pages that describes the different state managers and how/when you should use it [https://flutter.dev/docs/development/data-and-backend/state-mgmt/options](https://flutter.dev/docs/development/data-and-backend/state-mgmt/options).


 
 
## What Provider can do?
Provider can be used with `InheritedWidgets `and `StatefulWidgets`, or again, in place of them. It "does" two jobs:
- Separates your state from your UI
- Manages rebuilding UI based on state changes

**Providers allow to not only expose a value, but also create/listen/dispose it.** [source](https://pub.dev/packages/provider)



## Dependencies
```
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  provider: ^6.0.5
```


## Let's Start Write our codes
**1. Create Our Provider**
create a file called `notes_operation.dart`, and add this code
```
class NotesOperation with ChangeNotifier {
  //List of notes
  List<Note> _notes = [];

  List<Note> get getNotes {
    return _notes;
  }

  NotesOperation() {
    //addNewNote('First Note', 'First Note Description');
  }

  void addNewNote(String title, String description) {
    //Note object
    Note note = Note(title, description);
    _notes.add(note);
    notifyListeners();
  }
}
```

1. It extends `ChangeNotifier`, a class that “provides change notification to its listeners”. So you can listen to an instance of a `ChangeNotifier `and being notified when it changes.
2. It exposes the list of notes value which start with empty list.
3. We will use the `addNewNote `function to add note.
4. When the note added to list, changes the class will notify its listener using `notifyListeners()`.


Now we will need to add the Provider widget in our widget tree, in our case all the children of the `homeScreen` should display list of notes, so we sill need to wrap the `HomeScreen` widget in a Provider widget (in particular a `ChangeNotifierProvider` because we're using a ChangeNotifier). `ChangeNotifierProvider` needs a create parameter, it's the function that will be called to create our `NoteOperation`.

```
class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blueGrey,
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => AddScreen(),
            ),
          );
        },
        child: Icon(Icons.add, size: 30, color: Colors.blueGrey),
        backgroundColor: Colors.white,
      ),
      appBar: AppBar(
        title: Text(
          'Task Manager',
          style: TextStyle(
            fontSize: 25,
            fontWeight: FontWeight.bold,
          ),
        ),
        centerTitle: true,
        elevation: 0,
        backgroundColor: Colors.transparent,
      ),
      body: Consumer<NotesOperation>(
        builder: (context, NotesOperation data, child) {
          return ListView.builder(
            itemCount: data.getNotes.length,
            itemBuilder: (context, index) {
              return NotesCard(data.getNotes[index]);
            },
          );
        },
      ),
    );
  }
}

class NotesCard extends StatelessWidget {
  final Note note;

  NotesCard(this.note);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(15),
      padding: EdgeInsets.all(15),
      height: 150,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(15),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            note.title,
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          SizedBox(height: 5),
          Text(
            note.description,
            style: TextStyle(fontSize: 17),
          ),
        ],
      ),
    );
  }
}
```

Now we can display list of notes of out `NotesOperation`, to do so we need to use a Consumer widget.

The Consumer widget has a builder function that is called whenever the Provider needs to (basically when `notifyListeners `is called). The builder function has 3 parameters:

1. `context`: the context of this build
2. `NotesOperation`: our NotesOperation declared above. If the provider package doesn't find a parent with the correct Provider type it will throw an Exception.
3. `child`: you can optionally pass a child widget to the Consumer, that will be passed to the builder function in this parameter. This is here for optimization, if you have a big widget that doesn’t need the value exposed by the provider you can pass it as child and use it in the builder function.

Here’s an example of a text that display list of notes of our `NotesOperation` .
```
Consumer<NotesOperation>(
        builder: (context, NotesOperation data, child) {
          return ListView.builder(
            itemCount: data.getNotes.length,
            itemBuilder: (context, index) {
              return NotesCard(data.getNotes[index]);
            },
          );
        },
      )
```


## Why don’t you just call setState?
The obvious question that could come to your mind is “Why don’t you just use a StatefulWidget with setState?”. Here are some of the reasons:

1. One of the main reasons to prefer `Provider `over `Statefulwidgets `is that, using `Provider`, you will rebuild only the widgets that needs that value (the `Consumers`) while the other will not be rebuilt. Instead when you call `setState` the whole build function of the widget will be called.
2. You can use the values exposed by providers in other widgets without passing them. In our case, if you need to push a new Scaffold you can still use the mainColor with the Consumer because it will be a child of the Provider
3. You can have different Providers, that do different things using a [MultiProvider](https://pub.dev/packages/provider#multiprovider)
4. The allocation and disposal of objects is managed by the package and the objects are created lazily when they are needed.

full example: [github](https://github.com/samseptiano/flutter-note-app)