Riverpod: Notifier
חלק מהיחידה ניהול מצב במסלול ה-Flutter של Coddy. שיעור 19 מתוך 27.
StateProvider מתאים למספר אחד. כשהמצב מגיע עם כללים, כמו רשימה עם מתודות להוספה ולהסרה, כותבים Notifier: מחלקה שמחזיקה את המצב ואת המתודות שמשנות אותו.
class GuestList extends Notifier<List<String>> {
@override
List<String> build() => [];
void add(String name) {
state = [...state, name];
}
}
final guestsProvider =
NotifierProvider<GuestList, List<String>>(GuestList.new);build מחזירה את המצב הראשוני, רשימה ריקה. בתוך המחלקה, state הוא הערך הנוכחי. GuestList.new הוא הבנאי של המחלקה, שמועבר לספק כדי שיוכל ליצור את ה-notifier.
הכלל המרכזי: נותנים ל-state ערך חדש, לעולם לא משנים את הערך הישן. Riverpod מודיע לווידג'טים רק כאשר state מקבל אובייקט אחר. state.add(name) משנה את הרשימה במקום, כך ש-state עדיין מצביע לאותה רשימה ואיש לא מקבל על כך הודעה. [...state, name] יוצרת רשימה חדשה: שלוש הנקודות מפזרות לתוכה כל שם ישן, ואז השם החדש מתווסף בסוף.
ווידג'ט קורא למתודה דרך ה-notifier: ref.read(guestsProvider.notifier).add('Ada'). הדף הזה הוא ConsumerStatefulWidget, מהסוג ששומר מצב, כי הוא גם שומר בקר טקסט. ל-State שלו יש את ref כשדה.
אתגר
קשהרשימת האורחים מציגה את השמות שב־guestsProvider, אבל Add רק מנקה את השדה.
- הוסף ל־
GuestListמתודה בשםadd(String name)שמציבה ב־stateרשימה חדשה, כשהשם מופיע בסופה. - גרום ל־
Addלקרוא למתודה עם הטקסט שבשדה, לפני שהיא מנקה את השדה.
נסו בעצמכם
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class GuestList extends Notifier<List<String>> {
@override
List<String> build() => [];
}
final guestsProvider = NotifierProvider<GuestList, List<String>>(GuestList.new);
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: PartyPage(),
);
}
}
class PartyPage extends ConsumerStatefulWidget {
const PartyPage({super.key});
@override
ConsumerState<PartyPage> createState() => _PartyPageState();
}
class _PartyPageState extends ConsumerState<PartyPage> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final guests = ref.watch(guestsProvider);
return Scaffold(
appBar: AppBar(title: Text('Guests: ${guests.length}')),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: TextField(
controller: controller,
decoration: const InputDecoration(labelText: 'Guest name'),
),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () {
controller.clear();
},
child: const Text('Add'),
),
],
),
),
Expanded(
child: ListView(
children: [
for (final name in guests) ListTile(leading: const Icon(Icons.person), title: Text(name)),
],
),
),
],
),
);
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה ניהול מצב
תרגלו בעצמכם: קומפיילר Flutter אונליין