Menu
CoddyTech

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 setState trong 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,
challenge icon

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 MyApp thành ConsumerWidget, để themeMode theo dõi provider.
  • Chuyển SettingsScreen thành ConsumerWidget: 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;
              });
            },
          ),
        ],
      ),
    );
  }
}
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch Flutter online