Skip to content

Instantly share code, notes, and snippets.

@mono0926
Last active August 13, 2019 00:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mono0926/52c8441960cdd5b62aaf31d9eb336072 to your computer and use it in GitHub Desktop.
Save mono0926/52c8441960cdd5b62aaf31d9eb336072 to your computer and use it in GitHub Desktop.
import 'package:flutter/widgets.dart';
import 'package:rxdart/rxdart.dart';
/// - https://raw.githubusercontent.com/Kavantix/bloc_streambuilder/master/lib/src/value_observable_builder.dart
/// - https://twitter.com/_mono/status/1078948544784941058
class ValueObservableBuilder<T> extends StatefulWidget {
const ValueObservableBuilder({
Key key,
@required this.builder,
@required this.stream,
this.child,
}) : super(key: key);
final ValueObservable<T> stream;
final AsyncWidgetBuilder<T> builder;
final Widget child;
@override
_ValueObservableBuilderState createState() =>
_ValueObservableBuilderState<T>();
}
class _ValueObservableBuilderState<T> extends State<ValueObservableBuilder<T>> {
@override
Widget build(BuildContext context) {
return StreamBuilder<T>(
initialData: widget.stream.value,
stream: widget.stream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting &&
snapshot.hasData) {
snapshot = AsyncSnapshot<T>.withData(
ConnectionState.active,
snapshot.data,
);
}
return widget.builder(
context,
snapshot,
widget.child,
);
},
);
}
}
typedef AsyncWidgetBuilder<T> = Widget Function(
BuildContext context,
AsyncSnapshot<T> snapshot,
Widget child,
);
@macoshita
Copy link

こちらネストさせたときは注意が必要そうです。

ValueObservableBuilder<A>(
  builder: () {
    return ValueObservableBuilder<B>(
      builder: () {
        return Text(snapshotOfA.data + snapshotOfB.data);
      },
    );
  },
),

こんなコードで A stream に値が流れたとき、 A Builder のビルドは走りますが、 B Builder はスナップショットの差分がないのでビルドが走らず、 A を使っている Text の表示が変わらない、ということが起こります。

@mono0926
Copy link
Author

mono0926 commented Aug 9, 2019

@macoshita

そうですね、僕もちょっと罠だなと思いました。ただ、Widget層でネストさせずにモデル層で合成したストリームを流すのが望ましいとも思うので、これで良い気もしました。

とはいえ、困る場面もありそうなので、パッケージ版では reuseChild: false にすることでリビルド抑制をしないオプションもつけました。
https://github.com/mono0926/flutter_mono_kit/blob/master/lib/widgets/value_observable_builder.dart

@mono0926
Copy link
Author

mono0926 commented Aug 9, 2019

とはいえ、困る場面もありそうなので、パッケージ版では reuseChild: false にすることでリビルド抑制をしないオプションもつけました。

rebuild避けたい場合は、 child に指定すれば良いだけで、不要な最適化だと思い直したので、このGistおよびパッケージ版で常にリビルドするように変更しました。
( child で逃している部分はリビルド対象外のままです。)

@macoshita
Copy link

仰る通りなるべくネストはさせたくないですね。。
child は他にネットで見かけた StreamBuilder 拡張よりもよいなーと感じたので、自作のコードに採用させて頂いております 🙏
返信ありがとうございます!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment