Search code examples
flutterdartblocflutter-bloc

Can't access cubit in a modal with flutter_bloc


I have the following stateless widget. I'm trying to access the SettingsCubit in the SettingsOverlay class using BlocProvider.of<SettingsCubit>(context).updateSettings(newSettings); but it throws a ProviderNotFoundException. Also tried using a MaterialPageRoute instead of a modal, but it had the same problem.

The MovieBloc works correctly inside the MovieList widget with a BlocBuilder, and refreshes as it should.

Am I right, that it has something to do with that the MovieList is in the same widget tree as the BlocProvider, and the modal/new page is a different (sub)tree? If so, shouldn't the BlocProvider.value pass the data over to the SettingsOverlay?

Here is the widget's full code:

class MovieScreen extends StatelessWidget {
  const MovieScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<SettingsCubit>(
          create: (_) => SettingsCubit(),
        ),
        BlocProvider<MovieBloc>(
          create: (_) =>
              MovieBloc(httpClient: http.Client())..add(MovieFetched()),
        )
      ],
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Movies'),
          actions: [
            IconButton(
              onPressed: () => {
                showModalBottomSheet(
                  useSafeArea: true,
                  context: context,
                  builder: (_) {
                    return BlocProvider.value(
                      value: context.read<SettingsCubit>(),
                      child: const SettingsOverlay(),
                    );
                  },
                ),
              },
              icon: const Icon(Icons.add),
            ),
          ],
        ),
        body: const MovieList(),
      ),
    );
  }
}
class SettingsOverlay extends StatelessWidget {
  const SettingsOverlay({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Settings")),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: () {
              print("save");

              BlocProvider.of<SettingsCubit>(context)
                  .updateSettings(Settings());
            },
            child: const Text("Save"),
          ),
        ],
      ),
    );
  }
}

Solution

  • The issue is reading SettingsCubit on the same context where you've just created. context.read will look up the widget tree (not current one).

    You can add another builder for separate context.

     Builder(builder: (context) {
                  return IconButton(
                    onPressed: () {
                      showModalBottomSheet(
                        useSafeArea: true,
                        context: context,
                        builder: (_) {
                          return BlocProvider.value(
                            value: context.read<SettingsCubit>(),
                            child: const SettingsOverlay(),
                          );
                        },
                      );
                    },
                    icon: const Icon(Icons.add),
                  );
                }),