【问题标题】:How to use MultiBlocProvider and pass multiple provider in a child widget?如何使用 MultiBlocProvider 并在子小部件中传递多个提供程序?
【发布时间】:2021-07-24 13:45:32
【问题描述】:

我还在学习如何使用 bloc。目前我有两个集团,PostBloc 和 LocationBloc。 PostBloc 只会调用 api 来发布并拥有自己的演示 ui。 LocationBloc 只会获取位置,并且可以在任何功能中全局使用。我想在将其发布到服务器之前包含该位置。但我不知道如何使用这两个集团。下面的代码是我正在尝试做的一个例子。我不知道这是否是正确的方法。

class PostPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider(create: (_) => sl<PostBloc>()),
        BlocProvider(create: (_) => sl<LocationBloc>()),
      ],
      child: Scaffold(
        body: buildBody(),
      ),
    );
  }

  buildBody() {
    return BlocListener<PostBloc, PostState>(
      listener: (context, state) {
        if (state is Empty) {
        } else if (state is Loading) {
        } else if (state is Loaded) {
          //show snackbar
        } else if (state is Error) {}
      },
      child: InitialDisplay(),
    );
  }
}

class InitialDisplay extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          RaisedButton(onPressed: () {
            showDialog(
                barrierDismissible: false,
                context: context,
                builder: (_) {
                  return BlocProvider<PostBloc>.value(
                  value: BlocProvider.of<PostBloc>(context),
                  child: BlocProvider<LocationBloc>.value(
                      value: BlocProvider.of<LocationBloc>(
                          context),
                      child: PostDetails()));
                });
          }),
        ],
      ),
    );
  }
}

class PostDetails extends StatefulWidget {
  const PostDetails({Key key}) : super(key: key);
  @override
  _PostDetailsState createState() => _PostDetailsState();
}

class _PostDetailsState extends State<PostDetails> {
  double latitude;
  double longitude;

  @override
  Widget build(BuildContext context) {
    return BlocListener<LocationBloc, LocationBlocState>(
      listener: (context, state) {
        if (state is LocationBlocLoadedEvent) {
          latitude = state.location.latitude;
          longitude = state.location.longitude;
        }
      },
      child: Dialog(
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
          backgroundColor: Colors.transparent,
          child: _buildWidget(context)),
    );
  }

  _buildWidget(BuildContext context) {
    return Container(
        height: MediaQuery.of(context).size.height * .55,
        decoration: BoxDecoration(
            color: Colors.white,
            shape: BoxShape.rectangle,
            borderRadius: BorderRadius.circular(16)),
        child: RaisedButton(onPressed: () {
          postWithLocation();
        }));
  }

  void postWithLocation() {
    BlocProvider.of<LocationBloc>(context).add(LoadLocationEvent());
    BlocProvider.of<PostBloc>(context).add(PostEvent(
      post: 'Test post with location',
      long: longitude,
      lat: latitude,
    ));
  }
}

编辑: 这是我得到的错误。我认为这是因为我只通过 PostBloc,因为我不知道如何通过多个 bloc,或者这是否是正确的做法。

Error: Could not find the correct Provider<LocationBloc> above this BlocListener<LocationBloc, LocationBlocState> Widget

编辑 2: BlocLocation 现在正在工作。我刚刚传递了与 PostBloc 相同的 blocLocation 值。我现在的问题是 PostBloc 在postWithLocation() 函数中提交之前没有等待 LocationBloc 获取位置

BlocProvider<PostBloc>.value(
  value: BlocProvider.of<PostBloc>(context),
  child: BlocProvider<LocationBloc>.value(
      value: BlocProvider.of<LocationBloc>(
          context),
      child: PostDetails()));

【问题讨论】:

  • 您当前的解决方案有什么问题吗?
  • @Christian 我更新了问题并包含了我遇到的错误。

标签: flutter bloc flutter-bloc


【解决方案1】:

这是在Bloc 中执行序列作业的正确方法。

// _PostDetailsState
  @override
  Widget build(BuildContext context) {
    return BlocListener<LocationBloc, LocationBlocState>(
      listener: (context, state) {
        if (state is LocationBlocLoadedEvent) {
          final latitude = state.location.latitude;
          final longitude = state.location.longitude;
          BlocProvider.of<PostBloc>(context).add(PostEvent(
            post: 'Test post with location',
            long: longitude,
            lat: latitude,
          ));
        }
      },
      child: Dialog(
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
          backgroundColor: Colors.transparent,
          child: _buildWidget(context)),
    );
  }

同时删除postWithLocation中的一些代码。

  void postWithLocation(context) {
    BlocProvider.of<LocationBloc>(context).add(LoadLocationEvent());
  }

【讨论】:

  • 谢谢,这解决了我的问题。顺便说一句,您认为这是通过将其值传递给另一个小部件来使用MultiBlocProvider 的标准方式吗?或者有没有办法改进我上面的代码。非常感谢您的回复。
  • @unice 对我来说,这看起来像是标准方式。总的来说,这个包网站上的examples 非常擅长理解如何使用 BloC。
  • @unice 我重新检查了代码。如果你想在任何地方使用PostBlocLocationBloc,你应该在MaterialApp 上面使用MultiBlocProvider,然后不要再使用BlocProvider 包装。另一种方法是直接在PostDetails的构造函数中传递它,它可以更清晰和可测试的IMO。
猜你喜欢
  • 2020-10-06
  • 2020-08-25
  • 2021-04-02
  • 2021-09-28
  • 2023-02-14
  • 2021-11-09
  • 2022-01-17
  • 2018-11-14
  • 2020-09-27
相关资源
最近更新 更多