【问题标题】:Flutter riverpod widget is calling twiceFlutter Riverpod 小部件调用了两次
【发布时间】:2020-10-21 17:17:31
【问题描述】:

我正在尝试学习 Flutter 和 Riverpod,并尝试编写干净的代码。我刚刚注意到我的小部件被调用了两次。如何避免做不必要的操作?

我的项目只是一个导航栏,根据我们点击的按钮加载一个视图

我的 NavigationBarScreen :

class NavigationBarScreen extends HookWidget
{

  @override
  Widget build(BuildContext context) {

    print('build navigationScreen');
    final _pageModel = useProvider(navigationProvider.state);

    return SafeArea(
      child: Scaffold(
        body : context.read(navigationProvider).buildScreen(_pageModel.pageState),
        bottomNavigationBar: Container(
              margin: EdgeInsets.only(left : 8, right : 8, bottom: 8),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.only(
                    topRight: Radius.circular(20), topLeft: Radius.circular(20)),
                boxShadow: [
                  BoxShadow(color: AppColors.colorShadowLight, spreadRadius: 0, blurRadius: 10),
                ],
              ),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(50.0),
                child: BottomNavigationBar(
                  type: BottomNavigationBarType.fixed,
                  backgroundColor: AppColors.colorBgDark,
                  fixedColor: AppColors.colorContrastOrange,
                  unselectedItemColor: AppColors.colorFontLight2,
                  currentIndex: _pageModel.navigationIndexItem,
                  showSelectedLabels: false,
                  showUnselectedLabels: false,
                  onTap: context.read(navigationProvider).selectPage,
                  items: [
                    BottomNavigationBarItem(
                      icon: Icon(Icons.home),
                      title: Text('Home'),
                    ),
                    BottomNavigationBarItem(
                      icon: Icon(Icons.settings),
                      title: Text('Settings'),
                    ),
                  ],
                ),
              ),
            ),
      ),
    );
  }

}

我的导航通知器:

enum NavigationBarState
{
  HOME, PROFIL
}

class NavigationNotifier extends StateNotifier<NavigationBarModel>
{
  NavigationNotifier() : super(_initialPage);

  static const int _initialIndex = 0;
  static const NavigationBarState _initialState = NavigationBarState.HOME;
  static const _initialPage = NavigationBarModel(pageState : _initialState, navigationIndexItem : _initialIndex);

  void selectPage(int i)
  {
    switch (i)
    {
      case 0:
        state = NavigationBarModel(pageState : NavigationBarState.HOME, navigationIndexItem : i);
        break;
      case 1:
        state = NavigationBarModel(pageState : NavigationBarState.PROFIL, navigationIndexItem : i);
        break;
    }
  }

  Widget buildScreen(NavigationBarState page)
  {
    switch (page)
    {
      case NavigationBarState.HOME:
        return HomeScreen();
        break;
      case NavigationBarState.PROFIL:
        return Text("Page under construction");
        break;
    }
    return null;
  }

}

我的导航栏模型:

class NavigationBarModel {
  const NavigationBarModel({this.pageState, this.navigationIndexItem});
  final NavigationBarState pageState;
  final int navigationIndexItem;
}

在运行检查器中我有这个:

I/flutter (32738): build navigationScreen
I/flutter (32738): build homeScreen
I/flutter (32738): build navigationScreen
I/flutter (32738): build homeScreen

编辑:在我的navigationBarScreen中我改变了这个:

body : context.read(navigationProvider).buildScreen(_pageModel.pageState),

通过这个:

body : useProvider(navigationProvider).buildScreen(_pageModel.pageState),

context.read() 必须在onPressed、onTap、...中使用,但是我的结果是一样的,我的navigationBarScreen 被调用了两次...

【问题讨论】:

    标签: flutter dart riverpod


    【解决方案1】:

    由于缺少部分,我无法运行您的代码,但我最好的猜测是,因为您正在同时查看提供程序本身和提供程序状态,这就是它被调用两次的原因。

    @override
      Widget build(BuildContext context) {
    
        print('build navigationScreen');
        // Here you are listening to the state
        final _pageModel = useProvider(navigationProvider.state);
    
        return SafeArea(
          child: Scaffold(
            // Here you are listening to the provider
            body : context.read(navigationProvider).buildScreen(_pageModel.pageState),
    

    我建议重构 StateNotifier,而不是从 navigationProvider 状态获取 pageModel 并将其传递回 navigationProvider。

    class NavigationNotifier extends StateNotifier<NavigationBarModel>
    {
      NavigationNotifier() : super(_initialPage);
    
      static const int _initialIndex = 0;
      static const NavigationBarState _initialState = NavigationBarState.HOME;
      static const _initialPage = NavigationBarModel(pageState : _initialState, navigationIndexItem : _initialIndex);
    
      void selectPage(int i)
      {
        switch (i)
        {
          case 0:
            state = NavigationBarModel(pageState : NavigationBarState.HOME, navigationIndexItem : i);
            break;
          case 1:
            state = NavigationBarModel(pageState : NavigationBarState.PROFIL, navigationIndexItem : i);
            break;
        }
      }
    
      Widget buildScreen()
      {
        switch (state.pageState)
        {
          case NavigationBarState.HOME:
            return HomeScreen();
            break;
          case NavigationBarState.PROFIL:
            return Text("Page under construction");
            break;
        }
        return null;
      }
    
    }
    

    然后从构建方法的顶部删除final _pageModel = useProvider(navigationProvider.state);

    【讨论】:

    • 感谢您的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 2019-11-01
    • 2019-12-25
    • 2022-11-28
    • 2023-02-14
    • 1970-01-01
    相关资源
    最近更新 更多