Let me share my insights after working with 2 years with Flutter, Bloc and StatefulWidgets.
Whenever you find yourself in a situation that you want to make two StatefulWidget communicate, then think twice if Bloc is the answer! I have gone too far with bloc-everything approach as was suggested in their docs
and expected that bloc would help me achieve better modularity in code. I used BlocListeners to utilize listener: argument and call setState() in it... Then I tried with BlocBuilders. I have always reached the dead end and got many bugs while integrating StatefulWidget closely with Bloc. Why, you ask? Just to achieve this cleany, shiny modularity to have widgets in separate files and make them reusable and all that clean-code jazz.
However, that's not the case for StatefulWidget when it comes to practice.
Let me give you my mental model while approaching designing the widget. As for the example I will work on the following UI component - the vertical Column that contains two ListItems that every one composes of two Switches, where the top switch toggles the bottom one. When a parent preference switch is toggled off, then it also disables the child one.
Sample UI:

Video with such requirement to be fulfilled:

How to code such UI?
The first idea is to create:
- ParentPreferenceWidget.dart
- ChildPreferenceWidget.dart
- TitleSectionWidget.dart
Column would look like:
Column(
  children: [
    ParentPreferenceWidget(...),
    ChildPreferenceWidget(...),
    TitleSectionWidget(...),
    ParentPreferenceWidget(...),
    ChildPreferenceWidget(...),
    TitleSectionWidget(...),
  ]
)
Ok, so the UI was coded. And how to make those Swtiches communicate? (ParentPreferenceWidget with ChildPreferenceWidget one).
Well, the problem arises, as ParentPreferenceWidget and ChildPreferenceWidget will have a have Switch widget.
A Switch widget needs a value: parameter and is capable of running animation.
In every tutorial it is required to call setState for such Widget which aggregates Switch. So such widgets need to extend StatefulWidget.
A note for StatefulWidgets - their associated State objects have longer lifecylce than StatelessWidgets. And it made because of
performance reasons. Resource here.
So State objects are not destroyed during a widget tree rebuild phase, while StatelessWidgets are destroyed and recreated. This enables running the animation smoothly for the first case.
So how to use bloc then?
This could come to your mind (pseudo-code):
Column(
  children: [
    BlocProvider<...>(
      create: ...
      child: Column(
        children: [
           ParentPreferenceWidget(...), // will fire bloc events
           BlocBuilder<...>(
             builder: (context, state) => ChildPreferenceWidget(state, ...) // this will rebuild
           )  
        ]
      )
    ),
    TitleSectionWidget(...),
    BlocProvider<...>(
      create: ...
      child: Column(
        children: [
           ParentPreferenceWidget(...), // will fire bloc events
           BlocBuilder<...>(
             builder: (context, state) => ChildPreferenceWidget(state, ...) // this will rebuild
           )  
        ]
      )
    ),
    TitleSectionWidget(...),
  ]
)
Beware! Whenever event is fired, a new instance of PreferenceWidget is created. We've just said before that this is a StatefulWidget, hence no performance gain at all.
And also there will be bloc events multiplication (either you create separate bloc or reuse one). Either the new states are added and code complexity will grow.
And what if you want to move bloc higher? Like it would become a master one, so two ParentPreferenceWidget can communicate.
Then what you need to do, is to add more data to bloc events like bool wasFiredFromBlocA. This becomes a bloc hell.
Unfortunately, the only reasonable solution I came up with was to return to the basics and write the whole ParentPreferenceWidget and ChildPreferenceWidget functionality inside a single Stateful widget.
This is motivated by the problems mentioned about while using single  or multiple Blocs and making them communicate the state to child widgets.
So for my newly created Parent-Child widget, a State object contains two fields, like this:
bool _switchParentState;
bool _switchChildState;
And voila - this way state objects live as long as expected and handle the state correctly.
As for the bloc - you can manage such internal state with the help of BlocListener if you really want to listen to some parent bloc from the 'outside'.
This could look like this:
return BlocListener(
  listener: (context, state) {
    setState(() {
        // use state to set state
    });
  },
  child: ... // build the widget tree normally.
)
A note - just remember to use ValueKey or some other Key for any StatefulWidget that is duplicated inside the view hierarchy. As they need to be differentiated by the Flutter framework in case of State objects.
And that's how I perceive this after struggling a lot. The bloc is a great solution for simple cases. But when it comes to framework principles and some complex state mutations, it is better to stick to the basics.