首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >每当任何流发出值时,rx dart都会组合多个流来发出值。

每当任何流发出值时,rx dart都会组合多个流来发出值。
EN

Stack Overflow用户
提问于 2021-12-15 09:46:04
回答 4查看 1.4K关注 0票数 3

在RX中,有一个使用回调函数组合流结果的RX.combineLatest方法。问题是,只有当每个流发出一个值时,它才会发出一个值。如果一个人没有,它就不会发出。

每当任何流序列发出项时,通过使用组合器函数将给定的流合并成单个流序列。在所有流至少发出一项之后,流才会发出。

Im试图将多个流合并到一个流中进行验证,当流没有发出或发出空值时,应该发出false或true。

代码语言:javascript
运行
复制
class FormBloc {
  final BehaviorSubject<bool> _result = BehaviorSubject();
  final BehaviorSubject<String?> _usernameController = BehaviorSubject();
  final BehaviorSubject<String?> _emailController = BehaviorSubject();

  // Will only emit if each stream emitted a value
  // If only username is emitted valid is not emitted
  Stream<bool> get valid$ => Rx.combineLatest2(
    _usernameController.stream, 
    _emailController.stream, 
    (username, email) => username != null || email != null
  );

}

我如何加入这些流,以便如果valid$任何流的发生变化,它就会发出一个值?

EN

回答 4

Stack Overflow用户

发布于 2022-03-15 12:48:39

因为这里的所有解决方案都是解决方案,所以我实现了自己的流类。实现等于原始的CombineLatestStream实现,只是它不等待所有流发出后才发出:

代码语言:javascript
运行
复制
import 'dart:async';

import 'package:rxdart/src/utils/collection_extensions.dart';
import 'package:rxdart/src/utils/subscription.dart';

class CombineAnyLatestStream<T, R> extends StreamView<R> {

  CombineAnyLatestStream(List<Stream<T>> streams, R Function(List<T?>) combiner) : super(_buildController(streams, combiner).stream);

  static StreamController<R> _buildController<T, R>(
    Iterable<Stream<T>> streams,
    R Function(List<T?> values) combiner,
  ) {

    int completed = 0;

    late List<StreamSubscription<T>> subscriptions;
    List<T?>? values;

    final _controller = StreamController<R>(sync: true);

    _controller.onListen = () {

      void onDone() {
        if (++completed == streams.length) {
          _controller.close();
        }
      }

      subscriptions = streams.mapIndexed((index, stream) {

        return stream.listen(
          (T event) {
            final R combined;

            if (values == null) return;

            values![index] = event;

            try {
              combined = combiner(List<T?>.unmodifiable(values!));
            } catch (e, s) {
              _controller.addError(e, s);
              return;
            }

            _controller.add(combined);
          },
          onError: _controller.addError,
          onDone: onDone
        );
      }).toList(growable: false);

      if (subscriptions.isEmpty) {
        _controller.close();
      } else {
        values = List<T?>.filled(subscriptions.length, null);
      }
    };

    _controller.onPause = () => subscriptions.pauseAll();
    _controller.onResume = () => subscriptions.resumeAll();
    _controller.onCancel = () {
      values = null;
      return subscriptions.cancelAll();
    };

    return _controller;
  }

}
票数 2
EN

Stack Overflow用户

发布于 2022-02-12 05:59:44

创建新的流,它释放当前的价值,并倾听该流是我的最佳实践。

代码语言:javascript
运行
复制
class FormBloc {
  final BehaviorSubject<bool> _result = BehaviorSubject();
  final BehaviorSubject<String?> _usernameController = BehaviorSubject();
  final BehaviorSubject<String?> _emailController = BehaviorSubject();

  final _usernameStreamController = StreamController<String?>()
    ..add(_usernameController.value)
    ..addStream(_usernameController.stream);
  final _emailStreamController = StreamController<String?>()
    ..add(_emailController.value)
    ..addStream(_emailController.stream);

  Stream<bool> get valid$ => Rx.combineLatest2(
    _usernameStreamController.stream,  // use streamController instead
    _emailStreamController.stream,  // use streamController instead
    (username, email) => username != null || email != null
  );
}
票数 0
EN

Stack Overflow用户

发布于 2022-03-04 07:04:13

您可以使用一个BehaviorSubject<Map<String, String?>>来发出用户名或电子邮件中的更改,而不是组合多个流。

add要么更改\提交的用户名,要么向BehaviorSubject发送电子邮件

代码语言:javascript
运行
复制
_usernameEmailController.add({"uname": value},);

代码语言:javascript
运行
复制
_usernameEmailController.add({"email": value},);

这样您就可以通过侦听来验证输入。我使用StreamBuilder来显示发出的值,

代码语言:javascript
运行
复制
            StreamBuilder<Map<String, String?>>(
              stream: _usernameEmailController.stream
                  .map((data) {
                    _r = {..._r, ...data};
                    return _r;
                  }),
              builder: (context, snapshot) {
                return Column(
                  children: [
                    Text(snapshot.data.toString()),
                    if (snapshot.hasData)
                      Text(
                          "Is valid?: "
                          "${(snapshot.data!["uname"] != null && snapshot.data!["uname"]!.isNotEmpty) || (snapshot.data!["email"] != null && snapshot.data!["email"]!.isNotEmpty)}"
                      ),
                  ],
                );
              },
            ),

在DartPad 这里上查看我的解决方案。

在DartPad中,我使用了StreamController而不是BehaviorSubject,因为DartPad不支持rxdart包。但是您可以在DartPad中替换第40行

代码语言:javascript
运行
复制
final StreamController<Map<String, String?>> _usernameEmailController =
        StreamController();

使用

代码语言:javascript
运行
复制
final BehaviorSubject<Map<String, String?>> _usernameEmailController =
        BehaviorSubject();

如果您想使用BehaviorSubject

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70361479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档