Architecture/logic 问题 - 在这种情况下如何只重建一个消费者小部件? - 里弗波德

Architecture/logic issue- how do I rebuild only ONE Consumer widget in this scenario? - Riverpod

我真的把自己逼到了墙角,不知道如何重新设计以顺利解决这个问题,同时保持我的功能。我尝试将可重复使用的小部件在树中向上移动,但这很混乱并且没有用。我正在努力创建一个 Flutter 包,以防这可能会引发一些帮助。这是一个特定于我的错误 architecture/logic 的问题,也是一个关于如何使用 Riverpod 提供程序创建可重复使用的小部件以便仅更新必要的小部件的一般问题。

我的问题是我有一个“可重用”小部件 - “NumberButtonAnimation”,在这种情况下,我的“SequentialNavigator”父级中有 5 个。它们都是按钮,它们都在监听我的逻辑服务文件 navigatorServices 中的 pageIndex 值。因此,当页面索引更改时,它们都会重建,这当然是昂贵且不必要的。

如何添加逻辑或重新设计,以便只有移动按钮需要重建?

如果我认为钥匙还有用,我的想法是否正确?

/// LOGIC

final navigatorServices = ChangeNotifierProvider((ref) => NavigatorServices());

class NavigatorServices extends ChangeNotifier {
  StateCRUD stateCRUD = StateCRUD();
  int pageIndex = 1;
  int indexCount = 5;

  void nextPage() {
    if (pageIndex < indexCount) {
      pageIndex++;
      saveState();
      notifyListeners();
    }
  }

  void previousPage() {
    if (pageIndex > 1) {
      pageIndex--;
      saveState();
      notifyListeners();
    }
  }

  double buttonPosition(int buttonNumber) {
    double totalHeight = Get.height;
    double topPadding = WidgetsBinding.instance!.window.padding.top;
    double bottomPadding = WidgetsBinding.instance!.window.padding.bottom;
    double safeArea = totalHeight - (topPadding + bottomPadding);
    const double buttonWithPadding = 35.0;
    late double buttonTop;
    List<int> pageIndexes = [];
    int index = 0;
    // Current or past screen
    if (pageIndex >= buttonNumber) buttonTop = ((buttonWithPadding * buttonNumber) - buttonWithPadding);
    if (pageIndex < buttonNumber) {
      while (index < indexCount + 1) {
        pageIndexes.add(index);
        index++;
      }
      buttonTop = (buttonWithPadding * pageIndexes[buttonNumber]) + safeArea / 1.5;
    }
    return buttonTop;
  }

   ...
}


/// NUMBER BUTTON ANIMATION WIDGET

class NumberButtonAnimation extends StatelessWidget {
  const NumberButtonAnimation({Key? key, required this.buttonNumber}) : super(key: key);
  final int buttonNumber;

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, child) {
        print('Number button consumer built');
        return AnimatedPositioned(
          top: ref.watch(navigatorServices).buttonPosition(buttonNumber),
          curve: Curves.bounceOut,
          duration: const Duration(milliseconds: 500),
          child: NumberButton(number: buttonNumber),
        );
      },
    );
  }
}

/// PARENT WIDGET

class SequentialNavigator extends StatelessWidget {
  const SequentialNavigator({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 43.0,
      height: double.maxFinite,
      child: Stack(
        fit: StackFit.expand,
        alignment: Alignment.topCenter,
        children: [
          const NumberButtonAnimation(buttonNumber: 1),
          const NumberButtonAnimation(buttonNumber: 2),
          const NumberButtonAnimation(buttonNumber: 3),
          const NumberButtonAnimation(buttonNumber: 4),
          const NumberButtonAnimation(buttonNumber: 5),
        ],
      ),
    );
  }
}

当我点击下一个或上一个时的样子:

<5> flutter: Number button consumer built

这会打印 5 次,表示所有小部件正在重建,但只有一个按钮需要在任何更改时重建...

您可以使用 provider.select(...) 通过只获取您需要的内容来过滤重建

一个用法示例是:

Consumer(
  builder: (context, ref, child) {
    print('Number button consumer built');
    return AnimatedPositioned(
      top: ref.watch(navigatorServices.select((service) => service.buttonPosition(buttonNumber)),
      ...
    );
  },
);