使用 riverpod 进行简单的状态管理并不是读取 UI 处的状态变化

Using riverpod for simple state management is not reading state changes at UI

我要转到 Riverpod 并开始使用应该是非常简单的布尔状态管理来切换应用程序主题。我读过很多“如何”做这件事,但 none 专注于基础知识本身,使用过时的 API,使用不同的通知程序和提供程序,并添加比需要更多的功能。所以现在我迷路了。

版本:

简单的故事:

  1. 一个模型 class 扩展了 StateNotifier 并且其中有访问器和修改器用于 1 个布尔值
  2. 非常基本的应用程序 + 有状态小部件

问题:我可以看到,通过打印,状态正在改变,但是 UI 没有改变到状态改变时。我没有正确使用 StateNotifierStateProvider 作为简单的布尔状态吗?

感谢您的任何见解和指导!代码如下:

===

带有访问器/修改器的模型class

class RiverThemeDarkModel  extends StateNotifier<bool> {

  RiverThemeDarkModel() : super(false) {}

  bool get isDark  {
    print("model asked for dark status: ${state}");
    return state;
  }

  toggleDark() {
    print("toggler has listeners: ${hasListeners}");
    state = !state;
    print("toggled to: ${state}");
  }

  set isDark(bool value) {
    state = value;
  }

}

非常基本的应用程序 + 有状态小部件

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {

  runApp(ProviderScope(child: MyApp()));
}

final themeProvider = StateProvider((ref) =>  RiverThemeDarkModel());

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    final darkValueModel = ref.watch(themeProvider);

     print("consumer widget: dark value is ${darkValueModel.state} and listeners: ${darkValueModel.hasListeners}");
          return MaterialApp(
            title: 'Flutter Demo',
            debugShowCheckedModeBanner: false,
            theme: darkValueModel.isDark? ThemeData.dark() : ThemeData.light(),
            home: const MyHomePage(title: 'Flutter Demo Home Page'),
          );
        }

}

class MyHomePage extends ConsumerStatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  ConsumerState<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends ConsumerState<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    final darkValueModel = ref.watch(themeProvider);
print("build of state");
      return Scaffold(
        appBar: AppBar(
          title: Text(darkValueModel.isDark ? "Dark Mode" : "Light Mode"),
          actions: [
            IconButton(
                icon: Icon(darkValueModel.isDark
                    ? Icons.nightlight_round
                    : Icons.wb_sunny),
                onPressed: () {
                  ref.read(themeProvider).toggleDark();
                  print("Got pressed button, after setting is ${ref.read(themeProvider).isDark} \n\n");
                })
          ],
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'Something',
              ),
            ],
          ),
        ),
      );
    }
}

根据你的代码片段,你在这里做了什么

final themeProvider = StateProvider((ref) =>  RiverThemeDarkModel());

是为了让您的 UI 能够访问 class 的默认状态,这是错误的。因此,如果您将其更改为 true 并重新运行应用程序,它会更改主题。现在您要做的是公开对 class 的 stateNotifier 的访问权限,它会侦听 class 的状态变化并通知其侦听器。为此,您需要以这种方式使用 StateNotifierProvider...

final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
        (ref) =>  RiverThemeDarkModel());

现在帮助您实现的其余代码如下

为您的模型。

class RiverThemeDarkModel  extends StateNotifier<bool> {

  RiverThemeDarkModel() : super(false) {}

//u don't need this 'getter' piece of code 
  bool get isDark  {
    print("model asked for dark status: ${state}");
    return state;
  }

  toggleDark() {
    print("toggler has listeners: ${hasListeners}");
    state = !state;
    print("toggled to: ${state}");
  }

//neither do you need this
  set isDark(bool value) {
    state = value;
  }

}

为了你的UI...

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {

  runApp(ProviderScope(child: MyApp()));
}

final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
        (ref) =>  RiverThemeDarkModel());

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    final darkValueModel = ref.watch(themeProvider);

     print("consumer widget: dark value is ${darkValueModel.state} and listeners: ${darkValueModel.hasListeners}");
          return MaterialApp(
            title: 'Flutter Demo',
            debugShowCheckedModeBanner: false,
            theme: darkValueModel? ThemeData.dark() : ThemeData.light(),
            home: const MyHomePage(title: 'Flutter Demo Home Page'),
          );
        }

}

class MyHomePage extends ConsumerStatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  ConsumerState<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends ConsumerState<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    final darkValueModel = ref.watch(themeProvider);
print("build of state");
      return Scaffold(
        appBar: AppBar(
          title: Text(darkValueModel ? "Dark Mode" : "Light Mode"),
          actions: [
            IconButton(
                icon: Icon(darkValueModel
                    ? Icons.nightlight_round
                    : Icons.wb_sunny),
                onPressed: () {
                  ref.read(themeProvider.notifier).toggleDark();
                  print("Got pressed button, after setting is ${ref.read(themeProvider)} \n\n");
                })
          ],
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'Something',
              ),
            ],
          ),
        ),
      );
    }
}

也请查看文档。它阐明了一些您​​不会从大多数教程中得到的东西。 https://riverpod.dev/docs/concepts/reading

使用这个

final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
    (ref) => RiverThemeDarkModel());

而不是这个

最终主题提供者= StateProvider( (ref) => RiverThemeDarkModel());

对您的代码进行小改动

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(ProviderScope(child: MyApp()));
}

final themeProvider = StateNotifierProvider<RiverThemeDarkModel, bool>(
    (ref) => RiverThemeDarkModel());

class MyApp extends ConsumerWidget {
   MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final darkValueModel = ref.watch(themeProvider);

    print(
        "consumer widget: dark value is ${ref.read(themeProvider.notifier).state} and listeners: ${ref.read(themeProvider.notifier).hasListeners}");
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme:darkValueModel
          ? ThemeData.dark()
          : ThemeData.light(),
      home:  MyHomePage(title: 'Flutter Demo Home Page${ref.read(themeProvider.notifier).isDark}'),
    );
  }
}

class MyHomePage extends ConsumerStatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  ConsumerState<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends ConsumerState<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    final darkValueModel = ref.watch(themeProvider);
    print("build of state");
    return Scaffold(

      appBar: AppBar(
        title: Text(ref.read(themeProvider.notifier).isDark
            ? "Dark Mode${widget.title}"
            : "Light Mode"),
        actions: [
          IconButton(
              icon: Icon(ref.read(themeProvider.notifier).isDark
                  ? Icons.nightlight_round
                  : Icons.wb_sunny),
              onPressed: () {
                ref.read(themeProvider.notifier).toggleDark();
                print(
                    "Got pressed button, after setting is ${ref.read(themeProvider.notifier).isDark} \n\n");
              })
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              "Something ${ref.read(themeProvider.notifier).isDark} ",
            ),
          ],
        ),
      ),
    );
  }
}

class RiverThemeDarkModel extends StateNotifier<bool> {
  RiverThemeDarkModel() : super(false) {}

  bool get isDark {
    print("model asked for dark status: ${state}");
    return state;
  }

  toggleDark() {
    print("toggler has listeners: ${hasListeners}");
    state = !state;
    print("toggled to: ${state}");
  }

  set isDark(bool value) {
    state = value;
  }
}