CodeBlanks Logo Icon CodeBlanks

Challenge 1

Build API state management with StateNotifier and AsyncValue.

Challenge 1 - StateNotifier and AsyncValue

In this challenge you will create a StateNotifier<AsyncValue<List<String>>>. You wrap the API call with AsyncValue.guard, which handles loading and error states automatically.

class PostNotifier extends StateNotifier<AsyncValue<List<String>>> {
  PostNotifier() : super(const AsyncValue.loading()) {
    _load();
  }

  Future<void> _load() async {
    state = await AsyncValue.guard(() async => ['a', 'b']);
  }
}

Practice Define PostNotifier

Define PostNotifier extending StateNotifier<AsyncValue<List<String>>>. The constructor starts with AsyncValue.loading() and calls _load(). The async _load method assigns the result of AsyncValue.guard(() async => ['post1', 'post2']) to state. In main, create a PostNotifier instance, wait 100ms, and print state.value.

Starter code

main.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

// PostNotifier sınıfını tanımla (StateNotifier ve AsyncValue ile)
// constructor loading durumuyla başlasın ve _load çağırsın
// _load, state'e guard sonucunu atasın

void main() async {
  // PostNotifier örneği al, kısa bekle, state value'yu yazdır
}

Sample solution

main.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

class PostNotifier extends StateNotifier<AsyncValue<List<String>>> {
  PostNotifier() : super(const AsyncValue.loading()) {
    _load();
  }

  Future<void> _load() async {
    state = await AsyncValue.guard(() async => ['post1', 'post2']);
  }
}

void main() async {
  final notifier = PostNotifier();
  await Future.delayed(const Duration(milliseconds: 100));
  print(notifier.state.value);
  notifier.dispose();
}

Expected output

[post1, post2]

Practice Handle states with AsyncValue.when

In main, assign AsyncValue.data(['a', 'b']) to a variable state. Handle loading, data and error states with state.when: loading () => 'yukleniyor', data (v) => v.join(','), error (e, _) => 'hata: $e'. Print the result.

Starter code

main.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  // state değişkenine AsyncValue ile data durumu ata (liste: 'a' ve 'b')
  // .when ile loading, data ve error durumlarını işle
  // loading 'yukleniyor', data ile virgülle birleştir, error 'hata: $e'
  // sonucu yazdır
}

Sample solution

main.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  final state = AsyncValue.data(['a', 'b']);
  final result = state.when(
    loading: () => 'yukleniyor',
    data: (v) => v.join(','),
    error: (e, _) => 'hata: $e',
  );
  print(result);
}

Expected output

a,b

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 When should the state property of StateNotifier be updated?

  • When async operations complete and value is ready Correct answer
  • Never
  • Every frame
  • Only inside the constructor

Explanation: State gets its initial value in the constructor; it is updated with the guard result once async operations complete and the value is ready.

2 AsyncValue.guard call

Question
state = await AsyncValue.____(() async => ['a', 'b']);
Answer
state = await AsyncValue.guard(() async => ['a', 'b']);

Explanation: AsyncValue.guard wraps the given async function; it returns AsyncError on failure or AsyncData on success.

3 StateNotifier and AsyncValue matches

Term Meaning
StateNotifier State manager
AsyncValue Async state wrapper
guard Catches errors
StateNotifierProvider Provider

All lessons in Advanced