Riverpod StateNotifier 不适用于悬停逻辑

Posted

技术标签:

【中文标题】Riverpod StateNotifier 不适用于悬停逻辑【英文标题】:Riverpod StateNotifier not working with hover logic 【发布时间】:2022-01-17 10:28:14 【问题描述】:

我正在尝试使用 Riverpod 和它的 StateNotifier 来控制我的导航栏。以下是我的代码:

状态通知文件

import 'package:flutter_riverpod/flutter_riverpod.dart';

final navigationControllerRP =
    StateNotifierProvider<NavigationControllerRP, NavigationControllerElement>(
        (ref) => NavigationControllerRP());

class NavigationControllerRP
    extends StateNotifier<NavigationControllerElement> 
  NavigationControllerRP() : super(NavigationControllerElement("Home", ""));

  void changeActiveTo(String item) 
    state = NavigationControllerElement(item, "");
    state = state;
  

  void changeHoverTo(String item) 
    if (item != state.activeItem) 
      state = NavigationControllerElement(state.activeItem, item);
      state = state;
    
  

  bool isActive(String item) 
    return state.activeItem == item;
  

  bool isHover(String item) 
    return state.hoverItem == item;
  


class NavigationControllerElement 
  var activeItem = "";
  var hoverItem = "";

  NavigationControllerElement(this.activeItem, this.hoverItem);

通知器的使用文件

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get/get.dart';
import 'package:platform/constants/controllers.dart';
import 'package:platform/constants/style.dart';
import 'package:platform/controllers/navigation.dart';
import 'package:platform/widgets/custom_text.dart';

class NavBarElement extends ConsumerWidget 
  /// Creates a navbar element which can be displayed at the top of the page.
  final String title;
  final String url;
  final String route;

  NavBarElement(
    required this.title,
    required this.url,
    required this.route,
  );

  @override
  Widget build(BuildContext context, WidgetRef ref) 
    return InkWell(
      highlightColor: Colors.transparent,
      hoverColor: Colors.transparent,
      child: Padding(
          padding: EdgeInsets.all(20.0),
          child: Consumer(
            builder: (BuildContext context, WidgetRef ref, Widget? child) 
              return Column(
                children: [
                  CustomText(
                    text: this.title,
                    size: 16,
                    color: ref
                            .watch(navigationControllerRP.notifier)
                            .isActive(this.title)
                        ? Color.fromRGBO(70, 70, 70, 1)
                        : Colors.grey,
                    weight: FontWeight.w500,
                  ),
                  SizedBox(
                    height: 7,
                  ),
                  ref
                          .watch(navigationControllerRP.notifier)
                          .isActive(this.title)
                      ? Container(width: 50, height: 1, color: Colors.black)
                      : Container(),
                  ref.watch(navigationControllerRP.notifier).isHover(this.title)
                      ? Container(width: 50, height: 1, color: Colors.red)
                      : Container(),
                ],
              );
            ,
          )),
      onTap: () 
        ref.watch(navigationControllerRP.notifier).changeActiveTo(this.title);

        // navigationController.changeActiveTo(this.route);
        Get.toNamed(route);
      ,
      onHover: (value) 
        value
            ? ref
                .watch(navigationControllerRP.notifier)
                .changeHoverTo(this.title)
            : ref.watch(navigationControllerRP.notifier).changeHoverTo("none");
      ,
    );
  

我的 activeItem 逻辑工作正常,但 hoverItem 逻辑似乎不工作。每次我将鼠标悬停在导航栏元素上时,它似乎都在更新状态,即为我的 NavigationControllerElement 对象设置 hoverItem 但它不会反映在 UI 中。请让我知道如何解决这个问题。提前致谢!

【问题讨论】:

【参考方案1】:

您使用 StateNotifier 的方式不正确。 StateNotifier 不应该在 state 之外有任何可听的东西

特别是,您做错了什么是在 StateNotifier 上添加 getter/methods 以供 UI 使用:

class Model...

class MyNotifier extends StateNotifier<Model> 
  ...

  bool isActive(Item item) => state.activeItem == item; // DON'T DO THIS

然后用作:

final isActive: ref.watch(myProvider.notifier).isActive(myItem);

相反,这应该在您的状态类中:

class Model
  bool isActive(Item item) => activeItem == item;


class MyNotifier extends StateNotifier<Model> 

然后用作:

final isActive: ref.watch(myProvider).isActive(myItem);

【讨论】:

所以如果我想将它应用到 hoverItem,我只需添加一个函数 bool isActive(Item item) =&gt; hoverItem == item,对吗?

以上是关于Riverpod StateNotifier 不适用于悬停逻辑的主要内容,如果未能解决你的问题,请参考以下文章

如何覆盖 Riverpod StateNotifier 的状态以进行测试

消费者不使用 Riverpod 重建 UI

实施 ChangeNotifier 与 StateNotifier

Riverpod,在 BuildContext 和 Provider 之外读取状态

用 mockito 测试 Riverpod 的正确方法是啥

您应该将状态值放在 Riverpod 的啥位置?