使用返回按钮导航会导致丢失 BLoC 状态。

huangapple go评论60阅读模式
英文:

Navigating back with back button is making lose BLoC state

问题

使用返回按钮返回上一个屏幕会导致 BLOC 状态丢失。Flutter

我目前正在使用 flutter_bloc: ^8.1.3go_router: ^7.1.1。我有两个屏幕,一个是“显示物品屏幕”,另一个是“添加物品屏幕”。在“显示物品屏幕”中,我使用 initState() 来加载物品数据,并借助于 BLOC 工作得很好。但是,当我导航到“添加物品屏幕”并点击返回按钮时,“显示物品屏幕”会显示白屏,但它应该显示数据。以下是我的代码。

display_items_Screen.dart

class DisplayItemsScreen extends StatefulWidget {
  const DisplayItemsScreen({super.key});

  @override
  State<DisplayItemsScreen> createState() => _DisplayItemsScreenState();
}

class _DisplayItemsScreenState extends State<DisplayItemsScreen> {
  @override
  void initState() {
    super.initState();
    context.read<DisplayItemsBloc>().add(DisplayItemsLoadEvent());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.push("/add-items"),
        child: const Icon(Icons.add),
      ),
      appBar: AppBar(
        title: const Text("Display Items"),
      ),
      body: BlocConsumer<DisplayItemsBloc, DisplayItemsState>(
        listener: (context, state) {
          if (state is DisplayItemsErrorState) {
            showSnackBar("Something went wrong! please try again.");
          }
        },
        builder: (context, state) {
          if (state is DisplayItemsLoadingState) {
            return const LoadingView();
          } else if (state is DisplayItemsLoadedState) {
            final categories = state.userProductCategories;
            return DisplayItem(categories: categories); // 无状态小部件 GridView.builder()
          } else {
            return SizedBox.shrink();
          }
        },
      ),
    );
  }
}

add_items_screen.dart

class AddItemsScreen extends StatefulWidget {
  const AddItemsScreen({super.key});

  @override
  State<AddItemsScreen> createState() => _AddItemsScreenState();
}

class _AddItemsScreenState extends State<AddItemsScreen> {
  @override
  void initState() {
    super.initState();
    context.read<AddItemsBloc>().add(AddItemsLoadEvent());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Add Items"),
      ),
      body: BlocConsumer<AddItemsBloc, AddItemsState>(
        listener: (context, state) {
          if (state is AddItemsErrorState) {
            showSnackBar("Something went wrong! please try again.");
          }
        },
        builder: (context, state) {
          if (state is AddItemsLoadingState) {
            return const LoadingView();
          } else if (state is AddItemsLoadedState) {
            final items = state.loadedItems;
            return AddItem(categories: items);
          } else {
            return SizedBox.shrink();
          }
        },
      ),
    );
  }
}

router.dart

final navigatorKey = GlobalKey<NavigatorState>();

class AppRoutes {
  static routes() {
    return GoRouter(
      initialLocation: "/",
      navigatorKey: navigatorKey,
      routes: <RouteBase>[
        GoRoute(
          path: "/display-items",
          pageBuilder: (BuildContext _, GoRouterState state) {
            return CupertinoPage(
              child: const DisplayItemsScreen(),
              key: state.pageKey,
              restorationId: state.pageKey.value,
            );
          },
        ),
        GoRoute(
          path: "/add-items",
          pageBuilder: (BuildContext _, GoRouterState state) {
            return CupertinoPage(
              child: const AddItemsScreen(),
              key: state.pageKey,
              restorationId: state.pageKey.value,
            );
          },
        )
      ],
    );
  }
}

bloc_providers.dart

class BlocProviders {
  final DisplayItemsRepository _displayItemsRepository = DisplayItemsRepository();
  final AddItemsRepository _addItemsRepository = AddItemsRepository();

  blocs() {
    return [
      BlocProvider<DisplayItemsBloc>(
        create: (context) => DisplayItemsBloc(repository: _displayItemsRepository),
      ),
      BlocProvider<AddItemsBloc>(
        create: (context) => AddItemsBloc(repository: _addItemsRepository),
      ),
    ];
  }
}

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Hive.initFlutter();
  final BlocProviders blocProviders = BlocProviders();
  runApp(
    MultiBlocProvider(
      providers: blocProviders.blocs(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  MyApp({super.key});
  final _router = AppRoutes.routes();

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      scaffoldMessengerKey: snackbarKey,
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      themeMode: ThemeMode.light,
      routerConfig: _router,
    );
  }
}

希望这有助于解决您的问题。

英文:

Going back to previous screen by using back button is making lose BLOC State. Flutter

I'm currently using flutter_bloc: ^8.1.3 and go_router: ^7.1.1. I have two screens, one is
display items screen and another one is add items screen. In display items screen i'm using initState() to load the items data with the help of bloc and it is working fine. But when i navigate to add items screen and click on back button, the display items screen is showing white screen but it was suppose to show the data. Here is my code.

display_items_Screen.dart

class DisplayItemsScreen extends StatefulWidget {
  const DisplayItemsScreen({super.key});

  @override
  State&lt;DisplayItemsScreen&gt; createState() =&gt; _DisplayItemsScreenState();
}

class _DisplayItemsScreenState extends State&lt;DisplayItemsScreen&gt; {
  @override
  void initState() {
    super.initState();
    context.read&lt;DisplayItemsBloc&gt;().add(DisplayItemsLoadEvent());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () =&gt; context
            .push(&quot;/add-items&quot;)
            ,
        child: const Icon(Icons.add),
      ),
      appBar: AppBar(
        title: const Text(&quot;Display Items&quot;),
      ),
      body: BlocConsumer&lt;DisplayItemsBloc, DisplayItemsState&gt;(
        listener: (context, state) {
          if (state is DisplayItemsErrorState) {
            showSnackBar(&quot;Something went wrong! please try again.&quot;);
          }
        },
        builder: (context, state) {
          if (state is DisplayItemsLoadingState) {
            return const LoadingView();
          } else if (state is DisplayItemsLoadedState) {
            final categories = state.userProductCategories;
            return DisplayItem(categories: categories); // stateless widget GridView.builder()
          } else {  // it is running this else condition when navigated using back button
            return SizedBox.shrink();
          }
        },
      ),
    );
  }
}

add_items_screen.dart

class AddItemsScreen extends StatefulWidget {
  const AddItemsScreen({super.key});

  @override
  State&lt;AddItemsScreen&gt; createState() =&gt; _AddItemsScreenState();
}

class _AddItemsScreenState extends State&lt;AddItemsScreen&gt; {
  @override
  void initState() {
    super.initState();
    context.read&lt;AddItemsBloc&gt;().add(AddItemsLoadEvent());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
        title: const Text(&quot;Add Items&quot;),
      ),
      body: BlocConsumer&lt;AddItemsBloc, AddItemsState&gt;(
        listener: (context, state) {
          if (state is AddItemsErrorState) {
            showSnackBar(&quot;Something went wrong! please try again.&quot;);
          }
        },
        builder: (context, state) {
          if (state is AddItemsLoadingState) {
            return const LoadingView();
          } else if (state is AddItemsLoadedState) {
            final items = state.loadedItems;
            return AddItem(categories: items);
          } else {
            return SizedBox.shrink();
          }
        },
      ),
    );
  }
}

router.dart

final navigatorKey = GlobalKey&lt;NavigatorState&gt;();

class AppRoutes {
  static routes() {
    return GoRouter(
      initialLocation: &quot;/&quot;,
      navigatorKey: navigatorKey,
      routes: &lt;RouteBase&gt;[
        GoRoute(
            path: &quot;/display-items&quot;,
            pageBuilder: (BuildContext _, GoRouterState state) {
              return CupertinoPage(
                child: const DisplayItemsScreen(),
                key: state.pageKey,
                restorationId: state.pageKey.value,
              );
            },
           ),
        GoRoute(
            path: &quot;/add-items&quot;,
            pageBuilder: (BuildContext _, GoRouterState state) {
              return CupertinoPage(
                child: const AddItemsScreen(),
                key: state.pageKey,
                restorationId: state.pageKey.value,
               );
            },
           )
      ],
    );
  }
}

bloc_providers.dart

class BlocProviders {
  final DisplayItemsRepository _displayItemsRepository = DisplayItemsRepository();
  final AddItemsRepository _addItemsRepository =
      AddItemsRepository();

  blocs() {
    return [
      BlocProvider&lt;DisplayItemsBloc&gt;(
        create: (context) =&gt; DisplayItemsBloc(repository: _displayItemsRepository),
      ),
      BlocProvider&lt;AddItemsBloc&gt;(
        create: (context) =&gt; AddItemsBloc(repository: _addItemsRepository),
      ),
    ];
  }
}

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Hive.initFlutter();
  final BlocProviders blocProviders = BlocProviders();
  runApp(
    MultiBlocProvider(
      providers: blocProviders.blocs(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  MyApp({super.key});
  final _router = AppRoutes.routes();

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      scaffoldMessengerKey: snackbarKey,
      debugShowCheckedModeBanner: false,
      title: &#39;Flutter Demo&#39;,
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      themeMode: ThemeMode.light,
      routerConfig: _router,
      // routeInformationParser: AppRoutes.routes().routeInformationParser,
      // routeInformationProvider: AppRoutes.routes().routeInformationProvider,
      // routerDelegate: AppRoutes.routes().routerDelegate,
    );
  }
}

答案1

得分: 0

在你的 DisplayItemsBloc 代码中,可能是某个状态触发了。如果你提供你的 bloc 代码,将有助于理解。

但是,你可以在 BlocConsumer 中使用 buildWhen 函数来阻止构建不必要的状态:

buildWhen: (previous, current) =>
              current is DisplayItemsLoadingState || current is DisplayItemsLoadedState

并且你可以将你的构建器函数写成这样:

builder: (context, state) {
       if (state is DisplayItemsLoadedState) {
        final categories = state.userProductCategories;
        return DisplayItem(categories: categories); 
      } else { 
        return const LoadingView();
      }
    }

希望这对你有所帮助。

英文:

Maybe In your DisplayItemsBloc code some state is triggering.
If you provide your bloc code it would be good to understand.

But you can use buildWhen function in your BlocConsumer to stop building unnecessary states:

buildWhen: (previous, current) =&gt;
              current is DisplayItemsLoadingState || current is DisplayItemsLoadedState

and you can make your builder function like this:

builder: (context, state) {
       if (state is DisplayItemsLoadedState) {
        final categories = state.userProductCategories;
        return DisplayItem(categories: categories); 
      } else { 
        return const LoadingView();
      }
    },

huangapple
  • 本文由 发表于 2023年6月2日 00:37:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384020.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定