Ana içeriğe atla

StateNotifierProvider

StateNotifierProvider, bir StateNotifier'i (Riverpod'un yeniden ihraç ettiği state_notifier paketinden) dinlemek ve göstermek için kullanılan bir provider'dır.
StateNotifierProvider ve StateNotifier birlikte, kullanıcı etkileşimlerine tepki olarak değişebilecek durumu yönetmek için Riverpod'un önerilen çözümüdür.

Genellikle şunlar için kullanılır:

  • zamanla değişebilen değişmez bir durumu özel olaylara tepki olarak göstermek.
  • bir durumu değiştirmek için mantığı (iş mantığı olarak da bilinir) tek bir yerde merkezileştirerek zamanla bakım yeteneğini artırmak.

Bir kullanım örneği olarak, StateNotifierProvider kullanarak bir yapılacaklar listesi uygulayabiliriz. Bunu yapmak, kullanıcı etkileşimlerinde kullanıcı arayüzünün yapılacaklar listesini değiştirmesine izin vermek için addTodo gibi yöntemler sunmamıza olanak tanır:


// StateNotifier'ımızın durumu değişmez (immutable) olmalıdır.
// Uygulamada yardımcı olması için Freezed gibi paketler de kullanabiliriz.

class Todo {
const Todo(
{required this.id, required this.description, required this.completed});

// Sınıfımızdaki tüm özellikler `final` olmalıdır.
final String id;
final String description;
final bool completed;

// `Todo` değişmez olduğundan, içeriği biraz farklı olan
// bir `Todo` kopyası oluşturan bir yöntem uyguluyoruz.
Todo copyWith({String? id, String? description, bool? completed}) {
return Todo(
id: id ?? this.id,
description: description ?? this.description,
completed: completed ?? this.completed,
);
}
}

// StateNotifierProvider'ımıza geçirilecek StateNotifier sınıfı.
// Bu sınıf, durumunu "state" özelliği dışında açmamalıdır,
// yani getterlar/kamuya açık özellikler yok!
class TodosNotifier extends StateNotifier<List<Todo>> {
// `todos` listesini boş bir liste olarak başlatıyoruz.
TodosNotifier() : super([]);

// Kullanıcı arayüzünün todo eklemesine izin verelim.
void addTodo(Todo todo) {
// Durumumuz değişmez olduğundan, `state.add(todo)` yapamayız.
// Bunun yerine, önceki elemanları ve yenisini içeren yeni bir
// todos listesi oluşturmalıyız.
// Burada Dart'ın spread operatörünü kullanmak faydalıdır!
state = [...state, todo];
// "notifyListeners" veya benzeri bir şeyi çağırmaya gerek yoktur.
// "state =" çağırmak, gerektiğinde kullanıcı arayüzünü otomatik olarak yeniden oluşturacaktır.
}

// `todos` silmemize izin verelim
void removeTodo(String todoId) {
// Yine, durumumuz değişmez. Bu yüzden mevcut listeyi değiştirmek yerine yeni bir
// liste oluşturuyoruz.
state = [
for (final todo in state)
if (todo.id != todoId) todo,
];
}

// Bir `todo`yu tamamlandı olarak işaretleyelim
void toggle(String todoId) {
state = [
for (final todo in state)
// Sadece eşleşen `todo`yu tamamlandı olarak işaretliyoruz
if (todo.id == todoId)
// Yine, durumumuz değişmez olduğundan, bir kopya yapmamız gerekiyor.
// Bize yardımcı olması için daha önce uyguladığımız `copyWith` yöntemini kullanıyoruz.
todo.copyWith(completed: !todo.completed)
else
// diğer `todos` değiştirilmez
todo,
];
}
}

// Son olarak, kullanıcı arayüzünün TodosNotifier sınıfımızla etkileşimde bulunmasını
// sağlamak için StateNotifierProvider kullanıyoruz.
final todosProvider = StateNotifierProvider<TodosNotifier, List<Todo>>((ref) {
return TodosNotifier();
});

Artık bir StateNotifierProvider tanımladığımıza göre, kullanıcı arayüzümüzde todos listesi ile etkileşim kurmak için kullanabiliriz:


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


Widget build(BuildContext context, WidgetRef ref) {
// `todos` listesi değiştiğinde widget'ı yeniden oluştur
List<Todo> todos = ref.watch(todosProvider);

// `todos` öğelerini bir ListView içinde göstereceğiz
return ListView(
children: [
for (final todo in todos)
CheckboxListTile(
value: todo.completed,
// Bir `todo`ya dokunduğunuzda, durumunu tamamlanmış olarak değiştirin
onChanged: (value) =>
ref.read(todosProvider.notifier).toggle(todo.id),
title: Text(todo.description),
),
],
);
}
}