英文:
Navigating back with back button is making lose BLoC state
问题
使用返回按钮返回上一个屏幕会导致 BLOC 状态丢失。Flutter
我目前正在使用 flutter_bloc: ^8.1.3
和 go_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<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); // 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<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,
// 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) =>
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();
}
},
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论