tomoya.nagasaki
tomoya.nagasaki

Reputation: 127

Reading a state in a class that inherits from stateNotifier

I am trying to retrieve and delete a TodoList using flutter_riverpod's stateNotifierProvider. In the code below, the fetchTodoList method works fine, but the deleteTodoList method does not work.

UI

class TodoList extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final todoAsyncValue = watch(todoFutureProvider);
    return Padding(
      padding: const EdgeInsets.all(8),
      child: todoAsyncValue.when(
        data: (todoList) => SingleChildScrollView(
          child: Scaffold(
            body: Column(
              children: _buildTodoList(todoList),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: context.read(todoNotifierProvider.notifier).deleteTodoList(),
              child: const Icon(Icons.delete),
            ),
          ),
        ),
        loading: () => const Center(child: const CircularProgressIndicator()),
        error: (error, stack) => Text(error.toString()),
      ),
    );
  }
  _buildTodoList(){  // ......}
}

Provider & Class

final todoNotifierProvider = StateNotifierProvider<TodoListStateNotifier, List<Todo>>((ref) {
    return TodoListStateNotifier();
});

final todoFutureProvider = FutureProvider<List<Todo>>((ref) async {
    final todo= ref.read(todoNotifierProvider.notifier);
    await todo.fetchTodoList();
    return ref.watch(todoNotifierProvider);
});


class TodoListStateNotifier extends StateNotifier<List<Todo>>{
  TodoListStateNotifier(): super([]);

  Future<void> fetchTodoList() async {
    final todoClient = TodoClient();
    state = await todoClient.fetchTodoList(); 
  }

  void deleteTodoList() {
    var list = <Todo>[];
    list = state.removeLast();
    state = list;
  }
}

The following error message is displayed.

A value of type 'Todo' can't be assigned to a variable of type 'List'.

Also, if I convert the code to the following, the error is not displayed, but it is not reflected in the UI properly.

void deleteTodoList() {
    state.removeLast();
  }

I am assuming that the type defined in the following code is the type of the state, am I wrong?

class TodoListStateNotifier extends StateNotifier<List<Todo>>{

Is it not possible to read the state in the code?

Please let me know if you know a better way.

Upvotes: 0

Views: 531

Answers (2)

Alexandru Mariuti
Alexandru Mariuti

Reputation: 189

Every time when the UI rebuilds, the function is called. The error is here:

onPressed: context.read(todoNotifierProvider.notifier).deleteTodoList(),

you can remove the () or you can write:

onPressed: () => context.read(todoNotifierProvider.notifier).deleteTodoList(),

Upvotes: 0

croxx5f
croxx5f

Reputation: 5743

Here the removeLast() method returns a Todo exactly the last Todo in the list that's the why of the error

A value of type 'Todo' can't be assigned to a variable of type 'List'

Because you are indeed trying to assign a Todo to a List.

 void deleteTodoList() {
    var list = <Todo>[];
    list = state.removeLast();
    state = list;
  }

Now with the second example, here you effectively remove the last item but don't emit a new state, thus the UI does not rebuild.

void deleteTodoList() {
    state.removeLast();
  }

Alternatives:

  1. Filter and remove the specific todo you want
    state = state.where((todo) => todo.id != target.id).toList()
  1. Don't assign the removed value to the variable
  void deleteTodoList() {
    var list = <Todo>[];
state.removeLast();
    list=state;
    state = list;
  }
  1. Use the dart cascade operator and spread operators.

Use the spread operator(...) to make a copy of the list and the cascade operator for the applied method not to return the removed item.

  void deleteTodoList() {
    state=[...state..removeLast()];
  }  

Upvotes: 1

Related Questions