State Management in Flutter - Provider Journey with Todoey App
Tags: flutter, provider, statemanagement
Published: 2021-04-17 20:39:21

##Part 1 
###Use Provider to get data across the app
1 - Install Provider in .yaml file and get packages
2 - Build mindmap of a simple Provider implementation
3 - Build mindmap for Todoey app and Provider implementation

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mq0gvvgzrs1ivwc1h7t.JPG)
First areas of struggle - 
* How to use Provider with ListView and its tiles(parts 3 and 4)
* Buttons updating state (part 2)
4 - Start writing code
###Create TaskData class 
Properties tasks = []; (lift from tasks list)

Getter for taskCount 

`int get taskCount {
   return tasks.length;
 }`


Void addNewTasks() { // addTask to list ; notifyListeners(); }

`void addNewTasks(String newTaskTitle) {
   final task = Task(name: newTaskTitle);
   tasks.add(task);
   notifyListeners();
 }`


###Update root to access data at highest level
Got an error The argument type 'Widget Function(BuildContext)' can't be assigned to the parameter type 'Widget Function(BuildContext, Widget).
Turns out using builder is deprecated and we must use create instead. (April 16/ 2021). 

###Tasks Screen 
Update Text widget to provide number of tasks 
`'${Provider.of<TaskData>(context).tasks.length}',`
Comment out SetState in AddTaskScreen 
Convert to stateless widget since we are no longer using `setState` 
Update TaskListobject to not need any property constructors 


###Tasks List
Import provider and task_data 
Delete tasks property, won’t be needed anymore, the constructor is not needed either 
Replace ToDoItem constructor data, depending on which property you are trying to access
`Provider.of<TaskData>(context).tasks[index].name`
Also comment out `setState`
Convert to stateless widget since we are no longer using setState 

###The Consumer Widget from Provider
To not have to repeat all the places where `Provider.of<TaskData>(context).tasks[index].name` is going to be accessed. 
Wrap highest level widget where these will be used
In our case in Tasks List is the List View widget
End up with this
`return Consumer<TaskData>(
     builder: (context, taskData, child) {
       Return ListView….;
     },
     child: ListView.builder(`

Now taskData can replace `Provider.of<TaskData>(context)`

##Part 2 
Add Tasks to list functionality 
###AddTasks Screen
Button
`onPressed: () {
//newValue comes from textfield input 
             Provider.of<TaskData>(context, listen: false)
                   .addNewTasks(newTaskTitle);
               Navigator.pop(context);
             },`

##Part 3 
Functionality for tile’s state 
###Task Data
`void updateTask(Task task) {
   task.toggleDone();
 }`


###Task Tile
Tasks List (nothing specific to Provider, except for the use of updateTask)
`final task = taskData.tasks[index];
           return TodoItem(
               newTodoItem: task.name,
               tapped: task.isDone,
               iconCallBack: (bool checkBoxState) {
                 TaskData().updateTask(task);
               });`
With current setup, it should work, but Tasks Screen only updated when the button is pressed in the Add Tasks Screen. I think it is related to changes / updates in Provider. Related to that I had to set the listen: false . .. Maybe it is because we are using Consumer
 
SUCCESS! Because of changes made to the newer versions of Provider package, where we need to set the listen property to false. Even though we are inside Consumer, we still need to access updateTask calling through explicitly calling Provider to be able to set the listen property to false. This way the widget can rerender. 

    `final task = taskData.tasks[index];
           return TodoItem(
               newTodoItem: task.name,
               tapped: task.isDone,
               iconCallBack: (checkBoxState) {
                 Provider.of<TaskData>(context, listen: false)
                     .updateTask(task);
               });`


##Part 4 
###Delete Tasks 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8m69hxy6e8tguheuasvi.JPG)

1 create new method in TaskData model to delete the task 

 `void deleteTask(Task task) {
   _tasks.remove(task);
   notifyListeners();
 }`


2 - create a new callback in the TodoItem constructor 

`final Function longPressCallBack;
 TodoItem({this.newTodoItem, this.tapped, this.iconCallBack, this.longPressCallBack});`


3 - ListTile has a property - onLongPress, which is where we’ll call the new property in the constructor
 
`return ListTile(
     onLongPress: longPressCallBack,`


4 - Update TodoItem constructor in the TasksList Widget 

`longPressCallBack: () {
                 Provider.of<TaskData>(context, listen: false)
                     .deleteTask(task);
               },);`

5 - The TaskScreen creates a new TasksList Widget as a child, so it should get all this information and update. DONE!