Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ("partially") update AsyncValue in riverpod?

The riverpod (v2) documentation contains two great examples how a TODO-list could be implemented using either a Notifier or an AsyncNotifier. Both examples are functionally equivalent.

To pick one particular detail the non-async example contains a remove method like this

// Let's allow removing todos
void removeTodo(String todoId) {
  // Again, our state is immutable. So we're making a new list instead of
  // changing the existing list.
  state = [
    for (final todo in state)
      if (todo.id != todoId) todo,
  ];
}

Whereas the async version looks like this

// Let's allow removing todos
Future<void> removeTodo(String todoId) async {
  state = const AsyncValue.loading();
  state = await AsyncValue.guard(() async {
    await http.delete('api/todos/$todoId');
    return _fetchTodo();
  });
}

I'd now like to modify the async version to remove the deleted TODO item from it's internal state instead of re-fetching the whole collection via HTTP (which is what _fetchTodo does). I guess a practical reason could be to implement something like optimistic updates, but in this case it's rather a learning experience for me.

like image 977
Vinci Avatar asked Oct 17 '25 01:10

Vinci


1 Answers

If I understood correctly, you want to remove a TODO item from the list in the state without re-fetching everything from the API/scratch. In that case:

  1. You'd need to find the item inside the list inside the state,
  2. Copy that list,
  3. Remove that specific item in the list and
  4. Update the state.list with the item (found in step 2) removed.

Assuming you have a List<ToDoItem> listOfTodoItems inside your state, this is how you'd remove that item:

void updateToDoList(ToDoItem itemToRemove){
    //Step 1: find the index of the item we're searching the list for
    final indexOfSearchItem = listOfToDoItems.indexWhere((currentToDoItem)=> currentToDoItem == ToDoItem(toDoValue: 'Math class'));

    //Step 2: copy the whole list so we can replace the old list with the updated one
    final listToUpdate = state.listOfTodoItems;

    //Step 3: remove the item from the list we're going to update
    listToUpdate.removeAt(indexOfSearchItem);

    //Step 4: update the state's list with the new updated list
    state = state.copyWith(listOfTodoItems: listToUpdate);
}

Points to note, I directly used Equatable for this, but this could've been done by overriding == operator and hashCode methods.

I directly used copyWith method, again assuming that you already have this in your data class or generated using freezed package.

I used a simple sample of ToDoListItem but this idea applies to most of these examples. A more complex situation would be working with nested lists within nested lists in data classes.

This way you're only removing data within state management boundaries and you're not sending/receiving updated ToDoItem's to/from the backend.

like image 54
bqubique Avatar answered Oct 18 '25 17:10

bqubique



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!