简体   繁体   English

使用 riverpod 进行简单的 state 管理不是在 UI 读取 state 更改

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

I'm moving to Riverpod and starting with what should be a very simple boolean state management to switch the app theme.我要转移到 Riverpod 并从应该是一个非常简单的 boolean state 管理开始切换应用程序主题。 I've read many "how to" to do this exact thing, but none focus on the basics itself, are using outdated API, use different notifiers and providers, and add more features than needed.我读过很多“如何”做这件事,但没有人关注基础本身,使用过时的 API,使用不同的通知程序和提供者,并添加比需要更多的功能。 So now I'm lost.所以现在我迷路了。

versions:版本:

  • shared_preferences: ^2.0.13共享首选项:^2.0.13
  • flutter_riverpod: ^1.0.3 flutter_riverpod: ^1.0.3

Simple story:简单的故事:

  1. A model class that extends StateNotifier and has accessor and mutators in it for 1 single boolean value一个 model class,它扩展StateNotifier并在其中具有访问器和修改器,用于 1 个 boolean 值
  2. Very basic app + stateful widget非常基本的应用程序 + 有状态的小部件

Problem: I can see, via prints, the state is being altered, but the UI is not changing to when the state is changed.问题:我可以通过打印看到 state 正在被更改,但是 state 更改时 UI 没有更改。 Am I not using StateNotifier and StateProvider properly for a simple boolean state?我是否没有为简单的 boolean state 正确使用StateNotifierStateProvider

Thank you for any insight and guidance: Code follows:感谢您的任何见解和指导:代码如下:

=== ===

model class with accessors / mutators model 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; } }

Very basic app + stateful widget非常基本的应用程序 + 有状态的小部件

 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', ), ], ), ), ); } }

From your code snippet, what you did here从您的代码片段中,您在这里做了什么

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

was to provide to your UI access to the default state of your class which is false.是为您的 UI 提供对 class 的默认 state 的访问权限,这是错误的。 thus if you change it to true and rerun the app it changes the theme.因此,如果您将其更改为 true 并重新运行应用程序,它会更改主题。 now what you want to do is expose access to the stateNotifier of your class which listens to the state changes of the class and notifies its listeners.现在您要做的是公开对 class 的 stateNotifier 的访问权限,它会侦听 class 的 state 更改并通知其侦听器。 To achieve this you need to use a StateNotifierProvider this way...为此,您需要以这种方式使用 StateNotifierProvider ...

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

Now the rest of the code to help your implementation is as follows现在帮助你实现的代码rest如下

For your Model.为您的 Model。

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;
  }

}

For your 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',
              ),
            ],
          ),
        ),
      );
    }
}

Check out the documentation too.也查看文档。 It clarifies some things you won't get from most tutorials.它阐明了一些您不会从大多数教程中得到的东西。 https://riverpod.dev/docs/concepts/reading https://riverpod.dev/docs/concepts/reading

在此处输入图像描述

use this用这个

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

Instead of this而不是这个

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

Small Change on your code对您的代码进行小改动

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;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM