Flutter bloc - 不要每次都调用 api (在不同的视图中使用相同的状态)

Flutter bloc - do not call the api every time (use the same State in different views)

我在我的 flutter 应用程序中使用 flutter bloc pattern。我的底部导航栏在一页中有多个选项卡。其中两个使用相同的 api 调用(相同的状态)。当用户点击其中一个时,我调用 api 来获取数据,但如果用户点击另一个选项卡,我想获取数据而无需再次调用 api。我该怎么做?

在我的主页(仪表板)中,我使用 BlocBuilder 更改选项卡,并在其中创建仪表板 cubit

class DashboardPage extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
   return BlocBuilder<TabsBloc, AppTab>(
     builder: (BuildContext context, AppTab activeTab) {
       return Scaffold(
         appBar: AppBar(
           title: Text(DashboardHelpers.getTabLabel(activeTab)),
         ),
         body: RepositoryProvider(
           create: (BuildContext context) => DashboardRepository(),
           child: BlocProvider<DashboardCubit>(
             create: (BuildContext context) => DashboardCubit(
               dashboardRepository: context.read<DashboardRepository>(),
               authBloc: context.read<AuthBloc>(),
             ),
             child: DashboardHelpers.getTabContent(activeTab),
           ),
         ),
         bottomNavigationBar: TabSelector(
             activeTab: activeTab,
             onTabSelected: (tab) =>
                 BlocProvider.of<TabsBloc>(context).add(TabUpdated(tab))),
       );
     },
   );
 }
}

选项卡是作为子项加载的视图。其中一个视图是 View1。当我获取数据时,我在 ContentView1

中加载
class View1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    BlocProvider.of<DashboardCubit>(context)..getDashboardDevices();
    return BlocConsumer<DashboardCubit, DashboardState>(
      listener: (BuildContext context, DashboardState state) {
        if (state is DashboardError) {
          showDialog(
            context: context,
            builder: (context) => AlertDialog(
              content: Text(state.message),
            ),
          );
        }
      },
      builder: (BuildContext context, DashboardState state) {
        if (state is DevicesLoaded) {
          return ContentView1(data: state.data);
        } else if (state is DashboardLoading) {
          return LoadingWidget();
        } else if (state is DashboardError) {
          return Container(
            child: Center(
              child: Text(state.message),
            ),
          );
        } else {
          return Container();
        }
      },
    );
  }
}

和View2几乎一样。数据完全相同,并且加载到 ContentView2 中,但它是一个与 ContentView1

完全不同的小部件
class View2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    BlocProvider.of<DashboardCubit>(context)..getDashboardDevices();
    return BlocConsumer<DashboardCubit, DashboardState>(
      listener: (BuildContext context, DashboardState state) {
        if (state is DashboardError) {
          showDialog(
            context: context,
            builder: (context) => AlertDialog(
              content: Text(state.message),
            ),
          );
        }
      },
      builder: (BuildContext context, DashboardState state) {
        if (state is DevicesLoaded) {
          return ContentView2(data: state.data);
        } else if (state is DashboardLoading) {
          return LoadingWidget();
        } else if (state is DashboardError) {
          return Container(
            child: Center(
              child: Text(state.message),
            ),
          );
        } else {
          return Container();
        }
      },
    );
  }
}

问题是这两个视图显示来自同一 API 端点的不同数据。 当用户从 View1 切换到 View2 而无需再次调用 API 时,如何加载已获取的数据。

谢谢!

您应该只调用 getDashboardDevices() 一次,为此您可以创建一个 DashboardInitialState,当用户单击其中一个选项卡时,如果状态为 DashboardInitialState 您 运行 getDashboardDevices() 并不总是在构建视图时。这样,当构建其中一个视图时,您将只加载一次数据,并且它们都将在加载状态下使用相同的数据。

以 View1 为例,尝试使用两个视图:

class View1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<DashboardCubit, DashboardState>(
      listener: (BuildContext context, DashboardState state) {
        if (state is DashboardError) {
          showDialog(
            context: context,
            builder: (context) => AlertDialog(
              content: Text(state.message),
            ),
          );
        }
      },
      builder: (BuildContext context, DashboardState state) {
        if(state is DashboardInitialState) {
          BlocProvider.of<DashboardCubit>(context)..getDashboardDevices();
          return LoadingWidget();
        } else if (state is DevicesLoaded) {
          return ContentView1(data: state.data);
        } else if (state is DashboardLoading) {
          return LoadingWidget();
        } else if (state is DashboardError) {
          return Container(
            child: Center(
              child: Text(state.message),
            ),
          );
        } else {
          return Container();
        }
      },
    );
  }
}