skip to Main Content

I writing an app using flutter that add item to list (using simpleDialog) and show thus items in ListView when you add on.
The problem is that the list only update when I move to another page and them get to the list page, so the data is there. I just don’t understand how to make the list to re-render…

This is the provider I declare

@riverpod
List<Task> tasks(TasksRef ref) => [];

This is my widget how preset the list (tasks)

class TasksScreen extends StatefulHookConsumerWidget {
  const TasksScreen({super.key});

  @override
  ConsumerState<TasksScreen> createState() => _TasksScreenState();
}

class _TasksScreenState extends ConsumerState<TasksScreen> {
  @override
  Widget build(BuildContext context) {
    List<model.Task> tasks = ref.read(tasksProvider);
    List<Task> list = [];
    list = [...test(tasks)];

    return ProviderScope(
        child: Scaffold(
      body: ListView.builder(
        itemBuilder: (context, index) {
          return Task(task: ref.read(tasksProvider)[index]);
        },
        itemCount: ref.read(tasksProvider).length,
      ),
    ));
  }

  List<Task> test(List<model.Task> list) {
    List<Task> tasks = [];

    for (var i = 0; i < list.length; i++) {
      tasks.add(Task(task: list[i]));
    }

    return tasks;
  }
}

Thanks a lot for helpers !

I expecting that the changing of the provider lead to the list that render the page and show the list

2

Answers


  1. Sorry, i have never used the riverpod package before, so i can’t directly give you advice on this and you might have to wait for a different answer.

    But for the build method where you want to trigger rebuilds, you should use watch instead of read.

    And i don’t know if riverpod also has some wrapper, or helper class like a ChangeNotifier that you need to wrap your list in.

    Converted to the default provider package, a working example for your code snippet would look like:

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'dart:collection';
    
    class TaskStorage with ChangeNotifier {
      List<ModelTask> _myTasks = [];
    
      void add(ModelTask newTask) {
        _myTasks.add(newTask);
        notifyListeners();
      }
    
      UnmodifiableListView<ModelTask> get tasks => UnmodifiableListView<ModelTask>(_myTasks);
    }
    
    class ModelTask {
      int someData = 10;
    }
    
    class Task extends StatelessWidget {
      final ModelTask task;
    
      const Task({
        required this.task,
      });
    
      @override
      Widget build(BuildContext context) {
        return Text("task: ${task.someData}");
      }
    }
    
    class TasksScreen extends StatefulWidget {
      const TasksScreen({super.key});
    
      @override
      State createState() => _TasksScreenState();
    }
    
    class _TasksScreenState extends State<TasksScreen> {
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemBuilder: (context, index) {
                  return Task(task: context.watch<TaskStorage>().tasks[index]);
                },
                itemCount: context.watch<TaskStorage>().tasks.length,
              ),
            ),
            ElevatedButton(
              onPressed: () => context.read<TaskStorage>().add(ModelTask()),
              child: Text("ADD"),
            ),
          ],
        );
      }
    }
    
    void main() => runApp(
          MaterialApp(
            home: Scaffold(
              backgroundColor: Colors.green,
              appBar: AppBar(),
              body: ChangeNotifierProvider<TaskStorage>(
                create: (BuildContext context) {
                  return TaskStorage();
                },
                child: const TasksScreen(),
              ),
            ),
          ),
        );
    

    Maybe this could still help you. I would recommend looking at the documentation of the riverpod package.

    Login or Signup to reply.
  2. You should use watch instead of read since read does not rebuild the widget when the state change as describe in the document

    class TaskListNotifier extends StateNotifier<List<model.Task>> {
        TaskListNotifier() : super([]); // initial state
        void add(model.Task) {
            state.add(model.Task);
            state = [...state]; // this will notify and rebuild the UI
        }
    }
    
    final tasksProvider = StateNotifierProvider<TaskListNotifier, List<model.Task>>((ref) {
      return TaskListNotifier();
    });
    
    class TasksScreen extends StatefulHookConsumerWidget {
      const TasksScreen({super.key});
    
      @override
      ConsumerState<TasksScreen> createState() => _TasksScreenState();
    }
    
    class _TasksScreenState extends ConsumerState<TasksScreen> {
      @override
      Widget build(BuildContext context) {
        List<model.Task> tasks = ref.watch(tasksProvider);
    
        return ProviderScope(
            child: Scaffold(
          body: ListView.builder(
            itemBuilder: (context, index) {
              return GestureDetector(
              onTap: () {
                ref.read(tasksProvider.notifier).add(tasks[index]);
              },
              child: Task(task: tasks[index]),
              );
            },
            itemCount: tasks.length,
          ),
        ));
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search