Chọn nơi lưu trạng thái
Thuộc phần Quản lý trạng thái trong hành trình Flutter của Coddy. Bài học 21 trên 27.
Công tắc chế độ tối trên màn hình Settings di chuyển, nhưng không có gì chuyển sang tối. Giá trị của nó được lưu bằng setState, và chỉ công tắc mới đọc được. Chủ đề được thiết lập ở một nơi khác, trong MyApp. Giá trị này thuộc về toàn bộ ứng dụng.
Mỗi giá trị trong ứng dụng cần có một nơi lưu trữ. Hãy xác định ai sử dụng nó:
- Một widget (văn bản trong một trường, một bảng điều khiển đang mở, chỉ số tab): dùng
setStatetrong widget đó. - Một vài widget ở gần nhau (một nút và nhãn bên cạnh): chuyển giá trị lên widget cha rồi truyền xuống.
- Nhiều widget hoặc nhiều màn hình (người dùng, giỏ hàng, phần cài đặt): dùng một mô hình dùng chung với Provider hoặc Riverpod.
Provider hay Riverpod? Cả hai đều làm được việc này. Provider đơn giản hơn một chút và đặt các mô hình trong cây widget, có thể tìm thấy thông qua context. Riverpod giữ các provider bên ngoài cây, nên giá trị không cần context, và các provider có thể theo dõi lẫn nhau. Hãy chọn một giải pháp cho ứng dụng và dùng nó ở mọi nơi.
Ở đây, StateProvider phù hợp: một giá trị bool, được MyApp đọc để chọn chủ đề và được công tắc thay đổi:
final darkModeProvider = StateProvider((ref) => false);
// trong MyApp, giờ là ConsumerWidget:
themeMode: ref.watch(darkModeProvider) ? ThemeMode.dark : ThemeMode.light,Thử thách
KhóHãy để công tắc chế độ tối thay đổi toàn bộ ứng dụng:
- Thêm
final darkModeProvider = StateProvider((ref) => false);ở đầu. - Chuyển
MyAppthànhConsumerWidget, đểthemeModetheo dõi provider. - Chuyển
SettingsScreenthànhConsumerWidget: công tắc hiển thị giá trị của provider và cập nhật giá trị đó khi thay đổi.
Tự làm thử
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.light,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Notes'),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SettingsScreen()),
);
},
),
],
),
body: const Center(child: Text('No notes yet')),
);
}
}
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool dark = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: ListView(
children: [
SwitchListTile(
title: const Text('Dark mode'),
value: dark,
onChanged: (value) {
setState(() {
dark = value;
});
},
),
],
),
);
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Quản lý trạng thái
1Đưa state lên cấp trên
Truyền state cho component conTruyền callback cho component conCallback gửi giá trịĐưa state lên cấp trên4Riverpod
Riverpod: ProviderScopeConsumerWidget và ref.watchRiverpod: StateProviderRiverpod: NotifierCác provider theo dõi provider khácChọn nơi lưu trạng tháiTự luyện tập: Trình biên dịch Flutter online