Состояние постоянно вызывается.

Вопрос или проблема

После входа в систему, когда происходит перенаправление на главную страницу, инициализируются все страницы из widgetOptions. На странице корзины я вызываю API для получения корзины, а на странице профиля – API для получения профиля.

Моя проблема в том, что каждый раз, когда я попадаю на главную страницу, отображается домашняя страница, и при этом загружается API страницы профиля и API страницы корзины, и страница постоянно перестраивается снова и снова.

Я поставил отладчик на главную страницу, и он вызывается 5-10 раз в секунду. Состояние CartSuccessState вызывается несколько раз, так как страница постоянно пересоздается.


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

              @override
              State<RootPage> createState() => _RootPageState();
            }

            class _RootPageState extends State<RootPage>
                with AutomaticKeepAliveClientMixin {
              int _selectedIndex = 0;
              bool isInternetAvailable = false;

              final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
              final List<Widget> widgetOptions = <Widget>[
                const HomePage(),
                const CategoryPage(),
                const CartPage(),
                const ProfilePage(),
              ];
              void _onItemTapped(int index) {
                if (_selectedIndex != index) {
                  if (index == 2 || index == 3) {
                    if (HiveBoxData.getAccessToken() != "" &&
                        HiveBoxData.getCartID() != "") {
                      setState(() {
                        _selectedIndex = index;
                      });
                    } else {
                      showLoginBottomSheet(context);
                    }
                  } else {
                    setState(() {
                      _selectedIndex = index;
                    });
                  }
                }
              }

              late HomeBloc homeBloc;

              @override
              bool get wantKeepAlive => true;

              @override
              void initState() {
                BlocProvider.of<HomeBloc>(context).add(MainMenu());
                if (HiveBoxData.getAccessToken() != "" && HiveBoxData.getCartID() == "") {
                  BlocProvider.of<CartBloc>(context)
                      .add(CreateCart(customerAccessToken: HiveBoxData.getAccessToken()));
                } else if (HiveBoxData.getAccessToken() != "" &&
                    HiveBoxData.getCartID() != "") {
                  BlocProvider.of<CartBloc>(context)
                      .add(FetchCart(catID: HiveBoxData.getCartID()));
                }
                super.initState();
              }

           
              @override
              Widget build(BuildContext context) {
                super.build(context);
                return Scaffold(
                  key: _scaffoldKey,
                  appBar: AppBar(
                    forceMaterialTransparency: true,
                    actions: [
                      IconButton(
                        icon: const Icon(Icons.search),
                        onPressed: () async {
                          Navigator.pushNamed(
                            context,
                            Routes.searchPage,
                          );
                        },
                      ),
                      IconButton(
                        icon: const Icon(Icons.favorite_border),
                        onPressed: () {},
                      ),
                    ],
                    title: Row(
                      children: <Widget>[
                        Image.asset(
                          'assets/logo/shopify.png',
                          height: 40,
                          width: 30,
                        ),
                        const SizedBox(
                          width: 10,
                        ),
                        Text(
                          appName,
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                      ],
                    ),
                    leading: IconButton(
                      icon: const Icon(Icons.menu),
                      onPressed: () {
                        _scaffoldKey.currentState?.openDrawer();
                      },
                    ),
                  ),
                  drawer: const MyDrawer(),
                  bottomNavigationBar: BottomNavigationBar(
                    items: <BottomNavigationBarItem>[
                      BottomNavigationBarItem(
                        icon: const Icon(Icons.home),
                        label: AppLocalizations.of(context)!.home,
                      ),
                      BottomNavigationBarItem(
                        icon: const Icon(Icons.category),
                        label: AppLocalizations.of(context)!.category,
                      ),
                      BottomNavigationBarItem(
                        icon: Stack(
                          children: <Widget>[
                            const Icon(Icons.shopping_cart),
                            BlocConsumer<CartBloc, CartStates>(
                                listener: (context, state) {},
                                builder: (context, state) {
                                  print(state);
                                  if (state is CartSuccessState ||
                                      state is CartUpdateSuccessState) {
                                    return Positioned(
                                      right: 0,
                                      child: Container(
                                        padding: const EdgeInsets.all(1),
                                        decoration: BoxDecoration(
                                          color: Colors.red,
                                          borderRadius: BorderRadius.circular(6),
                                        ),
                                        constraints: const BoxConstraints(
                                          minWidth: 12,
                                          minHeight: 12,
                                        ),
                                        child: Text(
                                          "${BlocProvider.of<CartBloc>(context).nodes.length}",
                                          style: const TextStyle(
                                            color: Colors.white,
                                            fontSize: 8,
                                          ),
                                          textAlign: TextAlign.center,
                                        ),
                                      ),
                                    );
                                  } else {
                                    return const SizedBox();
                                  }
                                })
                          ],
                        ),
                        label: AppLocalizations.of(context)!.cart,
                      ),
                      BottomNavigationBarItem(
                        icon: const Icon(Icons.person),
                        label: AppLocalizations.of(context)!.profile,
                      ),
                    ],
                    currentIndex: _selectedIndex,
                    selectedItemColor: primaryMaterialColor,
                    unselectedItemColor: Colors.grey,
                    showUnselectedLabels: true,
                    onTap: _onItemTapped,
                    type: BottomNavigationBarType.fixed,
                  ),
                  body: BlocListener(
                      bloc: BlocProvider.of<HomeBloc>(context),
                      listener: (context, state) {
                        if (state is LogoutSuccessState) {
                          Navigator.pushNamedAndRemoveUntil(
                              context, Routes.logInPage, (Route<dynamic> route) => false);
                        }
                      },
                      child: IndexedStack(
                        index: _selectedIndex,
                        children: widgetOptions,
                      )),
                );
              }
            }

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

  @override
  State<ProfilePage> createState() => _ProfilePageState();
}

class _ProfilePageState extends State<ProfilePage> {
  late ProfileBloc profileBloc;

  @override
  void initState() {
    profileBloc = BlocProvider.of<ProfileBloc>(context);
    profileBloc.add(GetUserProfileDetails(
        customerAccessToken: HiveBoxData.getAccessToken()));

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return BlocConsumer(
        bloc: BlocProvider.of<ProfileBloc>(context),
        listener: (context, state) {},
        builder: (context, state) {
          if (state is ProfileSuccessState) {
            print(state);
            return Column(
              children: [
                DrawerHeader(
                  decoration: const BoxDecoration(
                    color: Colors.lightGreen,
                  ),
                  child: Padding(
                      padding: const EdgeInsets.only(left: 10, top: 16),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(state.name,
                              style: Theme.of(context).textTheme.titleLarge),
                          Text(state.email,
                              style: Theme.of(context).textTheme.titleMedium),
                        ],
                      )),
                ),
              ],
            );
          } else if (state is ProfileLoadingState) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          } else {
            return Container();
          }
        });
  }
}
class CartPage extends StatefulWidget {
  const CartPage({super.key});

  @override
  State<CartPage> createState() => _CartPageState();
}

class _CartPageState extends State<CartPage> {
  late CartBloc cartBloc;
  @override
  void initState() {
    cartBloc = BlocProvider.of<CartBloc>(context);
    cartBloc.add(FetchCart(catID: HiveBoxData.getCartID()));

    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
    cartBloc.nodes = [];
  }

  @override
  Widget build(BuildContext context) {
    return BlocConsumer(
      bloc: BlocProvider.of<CartBloc>(context),
      builder: (context, state) {
        if (state is CartSuccessState) {
          if (cartBloc.nodes.isNotEmpty) {
            return body();
          } else {
            return Center(
              child: Text(
                "В корзине нет товаров",
                style: Theme.of(context).textTheme.bodyMedium,
              ),
            );
          }
        } else if (state is CartLoadingState) {
          return const SingleChildScrollView(
              child: VerticalProductShimmer(productCount: 10));
        } else {
          if (cartBloc.nodes.isNotEmpty) {
            return body();
          } else {
            return const SingleChildScrollView(
                child: VerticalProductShimmer(productCount: 10));
          }
        }
      },
      listener: (context, state) {},
    );
  }

Ответ или решение

Проблема постоянного перезагрузки состояния в приложении

Описание проблемы

В вашем приложении, при входе и перенаправлении на главную страницу (Root Page), происходит инициализация всех страниц через список widgetOptions. Это приводит к тому, что при отображении главной страницы автоматически запускаются API для получения информации о пользоателей и корзине каждый раз, когда происходит перезагрузка страницы, что вызывает многоразовые вызовы состояния CartSuccessState. Дебаггер показывает, что состояние CartSuccessState вызывается 5-10 раз в секунду, что указывает на бесконечный цикл перезагрузки страниц.

Причины проблемы

  1. Неправильное управление состоянием: Вы вызываете API для получения профиля и корзины внутри метода initState класса _RootPageState. Эти вызовы происходят каждый раз, когда setState() обновляет виджет, что вызывает повторный билд и, соответственно, повторные вызовы API.
  2. Использование BlocProvider без контроля состояния: Вы используете BlocProvider для инициализации API, но не проверяете текущее состояние блока (например, было ли уже загружено состояние для пользователя или корзины).

Рекомендации по решению

  1. Измените логику вызова API:

    • Вместо того чтобы вызывать API в initState, вы можете использовать didChangeDependencies или контролировать изменение состояния, чтобы выполнить необходимый код только один раз:
    @override
    void didChangeDependencies() {
      super.didChangeDependencies();
      if (!profileBloc.state is ProfileLoaded) {
          profileBloc.add(GetUserProfileDetails(customerAccessToken: HiveBoxData.getAccessToken()));
      }
      if (!cartBloc.state is CartLoaded) {
          cartBloc.add(FetchCart(catID: HiveBoxData.getCartID()));
      }
    }
  2. Снизьте частоту вызовов состояния:

    • Убедитесь, что вы не вызываете setState() без необходимости. Это прекратит бесконечное построение виджета и вызовы соответствующих блоков.
  3. Используйте IndexedStack:

    • IndexedStack уже сохраняет состояние, поэтому при переключении между вкладками состояние не теряется. Убедитесь, что вы используете setState() только когда это действительно необходимо.
  4. Проверьте состояние на уровне представления:

    • Вы также можете добавить дополнительные проверки состояния в ваших виджетах ProfilePage и CartPage:
    @override
    Widget build(BuildContext context) {
       return BlocConsumer<ProfileBloc, ProfileState>(
           listener: (context, state) {
               // Реакция на изменение состояния
           },
           builder: (context, state) {
               if (state is ProfileLoadingState) {
                   return const CircularProgressIndicator();
               } else if (state is ProfileSuccessState) {
                   return ...; // Ваш виджет
               }
               return Container();
           }
       );
    }

Заключение

Следуя приведенным рекомендациям, вы сможете стабилизировать ваше приложение и предотвратить постоянные вызовы состояния, что в свою очередь улучшит производительность и пользовательский опыт. Важно всегда контролировать состояние приложения и избегать лишних вызовов API, особенно в условиях, когда состояния уже загружены.

Оцените материал
Добавить комментарий

Капча загружается...