31

まず、BLoC がどのように動作するか、その背後にある考え方を知っており、コンストラクターとの違いを知っていBlocProvider()ますBlocProvider.value()

簡単にするために、私のアプリケーションには次のようなウィジェット ツリーを含む 3 つのページがあります。

App()=> LoginPage()=> HomePage()=>UserTokensPage()

ユーザーなどにログインする必要があるため、LoginPage()アクセスできるようにします。そのために、次のようにウィジェットでビルダーをラップします。UserBlocLoginPage()App()

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      home: BlocProvider<UserBloc>(
        create: (context) => UserBloc(UserRepository()),
        child: LoginPage(),
      ),
    );
  }
}

それは明らかにうまく機能します。次に、ユーザーが正常にログインすると、ユーザーは に移動しHomePageます。ここで、自分の 2 つの異なるブロックにアクセスする必要があるため、HomePage既存のものをさらにMultiBlocProvider渡しUserBloc、 という名前の新しいブロックを作成しますDataBloc。私はこのようにします:

  @override
  Widget build(BuildContext context) {
    return BlocListener<UserBloc, UserState>(
      listener: (context, state) {
        if (state is UserAuthenticated) {
          Navigator.of(context).push(
            MaterialPageRoute<HomePage>(
              builder: (_) => MultiBlocProvider(
                providers: [
                  BlocProvider.value(
                    value: BlocProvider.of<UserBloc>(context),
                  ),
                  BlocProvider<DataBloc>(
                    create: (_) => DataBloc(DataRepository()),
                  ),
                ],
                child: HomePage(),
              ),
            ),
          );
        }
      },
[...]

これも機能します。HomePage ユーザーからに移動すると、問題が発生しますUserTokensPage。コンストラクターで渡したいUserTokensPage既存のものが必要です。私はこのようにします:UserBlocBlocProvider.value()

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: false,
        title: Text('My App'),
        actions: <Widget>[
          CustomPopupButton(),
        ],
      ),

[...]

class CustomPopupButton extends StatelessWidget {
  const CustomPopupButton({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<String>(
      icon: Icon(Icons.more_horiz),
      onSelected: (String choice) {
        switch (choice) {
          case PopupState.myTokens:
            {
              Navigator.of(context).push(
                MaterialPageRoute<UserTokensPage>(
                  builder: (_) => BlocProvider.value(
                    value: BlocProvider.of<UserBloc>(context),
                    child: UserTokensPage(),
                  ),
                ),
              );
            }
            break;
          case PopupState.signOut:
            {
              BlocProvider.of<UserBloc>(context).add(SignOut());
              Navigator.of(context).pop();
            }
        }
      },
[...]

ボタンを押して移動するMyTokensPageと、次のメッセージでエラーが発生します。

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building Builder(dirty):
        BlocProvider.of() called with a context that does not contain a Bloc of type UserBloc.

        No ancestor could be found starting from the context that was passed to BlocProvider.of<UserBloc>().

        This can happen if:
        1. The context you used comes from a widget above the BlocProvider.
        2. You used MultiBlocProvider and didn't explicity provide the BlocProvider types.

        Good: BlocProvider<UserBloc>(create: (context) => UserBloc())
        Bad: BlocProvider(create: (context) => UserBloc()).

        The context used was: CustomPopupButton

私は何を間違っていますか?PopupMenuButtonどういうわけかブロックを失うウィジェットを抽出したからですか?何が間違っているのかわかりません。

4

6 に答える 6

1

ウィジェットを 2 つのウィジェットに分解する (テスト容易性の理由からこれをお勧めします) か、Builder ウィジェットを使用して子コンテキストを取得する必要があります。

class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( create: (_) => TestCubit(), child: MyHomeView(), ); } } class MyHomeView extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: RaisedButton(onPressed: () => BlocProvider.of<TestCubit>(context)...) ), ); } }

出典: Felix Angelov が解決、https://github.com/felangel/bloc/issues/2064

于 2021-05-28T12:18:40.020 に答える