Трепещущий начальный маршрут с использованием значения поставщика

#flutter #dart #flutter-provider #flutter-navigation

#трепещущий #dart #трепетание-поставщик #трепещущая навигация

Вопрос:

Я только начал использовать provider в качестве управления состоянием для flutter. У меня есть значение в поставщике, которое будет использоваться для первоначального входа в систему. isLogin вернет true или false и в зависимости от этого перенаправит пользователя на домашнюю страницу или страницу входа в систему. Я получаю сообщение об ошибке ниже:

Не удалось найти правильного поставщика над этим виджетом MyApp

Кроме того, это хороший способ проверки подлинности или есть лучший способ. Я использую laravel API для аутентификации.

Main.dart

 void main() {
  runApp(MyApp());
}

@override
Widget build(BuildContext context) {
  return ChangeNotifierProvider<UserProvider>(
      create: (context) => UserProvider(),
      child: MaterialApp(
      initialRoute:Provider.of<UserProvider>(context,listen:false).isLogin?'/':'/login',
      routes: {
        '/':(_)=>HomePage(),
        '/donation-history':(_)=>DonationHistoryPage(),
        '/login':(_)=>LoginPage(),
        '/new-donation':(_)=>NewDonation()
      },
      debugShowCheckedModeBanner:false,
      title: 'RedHero',
      theme: ThemeData(
        primaryColor: kPrimaryColor,
        accentColor: Colors.white,
        scaffoldBackgroundColor: kBackgroundColor,
        fontFamily: "Poppins",
        textTheme: TextTheme(
          bodyText1: TextStyle(color: kBodyTextColor)
        )
      ),
    ),
  );
}
  

Комментарии:

1. Все в порядке, но как насчет моей первоначальной проблемы? Я не могу найти ошибку, я проверяю дерево виджетов, и поставщик находится поверх всех моих маршрутов @ Uni

2. приведенный выше виджет принадлежит MyApp @Uni

Ответ №1:

Нарушенный шаблон:

 class OuterWidget : StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Something>(
      ... Provider.of<Something>(context) ...
    );
  }
}
  

Проблема в том, что Provider.of<Something> получает то же context , что было передано build функции. В этом контексте ChangeNotifierProvider не существует; поставщик добавляется только в контексты сборки потомков, которые создаются при создании дочерних виджетов.

Если это неясно, представьте извлечение предоставленного объекта в переменную (что не меняет смысла кода):

 class OuterWidget : StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final something = Provider.of<Something>(context);
    return ChangeNotifierProvider<Something>(
      ... something ...
    );
  }
}
  

Теперь совершенно очевидно, что мы пытаемся использовать объект, который еще не был предоставлен.

Таким образом, одним из решений является разделение внутренней части на отдельный виджет:

 class OuterWidget : StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Something>(
      ... InnerWidget() ...
    );
  }
}

class InnerWidget : StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ... Provider.of<Something>(context) ...;
  }
}
  

Этот виджет получит новый дочерний контекст, в котором поставщик действительно существует.

Другим решением является использование Consumer виджета, который существует именно для этого сценария:

 class OuterWidget : StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Something>(
      ...
      Consumer<Something>(builder: (_, something, __) => ... something ...)
      ...
    );
  }
}
  

Теперь сборка дочерних элементов Consumer откладывается до builder метода, который, следовательно, также получает контекст сборки, в котором существует поставщик.