flutterdartriverpodappwriteriverpod-annotation

Is it ok make a call to an API in the build of a riverpod NotifierProvider?


It's a simple ToDo app with a login feature using appwrite as the backend. The problem is that when I log in, I do a ref.read to the method and it download the user tasks but when its logged and have to go directly to the task screen it uses a ref.watch where the build don't do the call to the backend.

Is it okay to make a call to a backend in the build() of a NotifierProvider?

void main() {
  runApp(const ProviderScope(child: MainApp()));
}

class MainApp extends ConsumerWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      // home: user.$id? LoginForm() : const ToDoScreen(),
      home: ref.watch(appwriteExistingUserProvider).when(
            data: (user) {
              if (user != null) {
                return const ToDoScreen();
              }
              return LoginForm();
            },
            error: (error, st) => Text(error.toString()),
            loading: () => const Center(child: CircularProgressIndicator()),
          ),
    );
  }
}
@Riverpod(keepAlive: true)
class TodoController extends _$TodoController {
  @override
  TodoState build() {
    return const TodoState(todosMap: <String, ToDoModel>{
      '1': ToDoModel(task: "task", documentId: "documentId")
    }, loading: true);
  }

  Future<void> getTodos() async {
    TodoRepository todoRepository = TodoRepository(ref);
    state = state.copyWith(loading: true);
    try {
      final todos = await todoRepository.getTodos();
      state = state
          .copyWith(todosMap: {for (ToDoModel v in todos) v.documentId: v});
    } finally {
      state = state.copyWith(loading: false);
    }
  }
}

Solution

  • Yes, you need to do this in the build method. However, your provider will then become an AsyncNotifier and the state will become Future<TodoState>. There will be no recalls during rebuilds (or you can make a timer), since you are using state caching via @Riverpod(keepAlive: true).