Flutter Bloc 从不同的小部件更改状态

Flutter Bloc change state from different widget

在我的应用程序主页上,我有一个列表视图,只要用户单击新页面就会重建。 我已经使用 flutter_bloc 插件实现了块模式,但我不知道如何从另一个小部件更改状态。

您可以将 BlocProvider 放置到一个共同的祖先,例如 MaterialApp 小部件的父级,或者您可以像这样将 bloc 传递到您的新页面:

BlocProvider.value(
  value: BlocProvider.of<BlocA>(context),
  child: ScreenB(),
);

使用 flutter bloc 改变状态需要记住两点:

  • 一个区块的依赖注入 (DI)。
  • 与您的 bloc 实例互动。

一个区块的依赖注入

情况1.您需要在一个路由中为widget子树提供bloc。


要向子树中的多个小部件提供 bloc 的单个实例,您可以使用 BlocProvider 小部件。它创建 bloc 实例,在需要时自动处理它并通过 BlocProvider.of<T>(context) 向其子级提供 bloc,其中 T 是您的 bloc 的名称:

BlocProvider(
  create: (BuildContext context) => BlocA(),
  child: ChildA(),
);

请记住,默认情况下它是用 属性 lazy: true 创建的,这意味着 create: (BuildContext context) => BlocA(), 将在调用 BlocProvider.of<T>(context) 之后执行。如果您不想要它 - 提前设置 lazy: false

情况 2. 您需要从另一条路线(到另一条上下文)向小部件提供 bloc。


BlocProvider 自动处理带有实例化新路由上下文的 bloc 实例,但如果您使用 BlocProvider.value:

则不会发生这种情况
BlocProvider.value(
  value: BlocProvider.of<BlocA>(context),
  child: ScreenA(),
);

重要提示:BlocProvider.value 只能用于为新子树提供现有实例,不要用它创建 Bloc 实例

与您的 bloc 实例互动

bloc v6.1.0 开始,context.bloccontext.repository 已弃用,取而代之的是 context.readcontext.watch

context.select 允许根据 bloc 状态的一部分更新 UI:

    final name = context.select((UserBloc bloc) => bloc.state.user.name);

context.read 使用 BuildContext 访问一个 bloc 并且不会导致重建。 context.watch 从与其类型最近的祖先提供者获取值并订阅该提供者。

访问区块状态

如果您需要一个小部件重建由于 bloc 值更改使用 context.watchBlocBuilder:

// Using context.watch at the root of the build method will result in the entire widget being rebuilt when the bloc state changes. 
@override
Widget build(BuildContext context) {
  final state = context.watch<MyBloc>().state;
  return Text('$state');
}

BlocBuilder:

// If the entire widget does not need to be rebuilt, either use BlocBuilder to wrap the parts that should rebuild
@override
Widget build(BuildContext context) {
  return BlocBuilder<MyBloc, MyState>(
    builder: (context, state) => Text('$state'),
  );
}

访问区块以便添加事件

使用context.read:

@override
Widget build(BuildContext context) {
  return ElevatedButton(
    onPressed: () => context.read<MyBloc>().add(MyEvent()),
    ...
  )
}