Flutter BLoC, RxDart SubmitedcombineLatestStream
- reactivex.io
- github.com/ReactiveX/rxdart
- pub.dev/packages/rxdart
- rxdart package documentatio
- rxmarbles.com/#combineLatest
- CombineLatestStream-class.
- ReactiveX 라이브러리 제품군 제외.
- 스트림 작업을위한 도우미 "객체 / 함수"있음
- 각 버전은 유사하며 때로는 약간의 차이가 있습니다.
- ReactiveX는 언어간에 유사해야하기 때문에 Dart가 사용하는 용어와 다른 용어를 사용합니다.
pubspec.yaml
# ...
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
rxdart: ^0.24.1
#rxdar: ^0.16.7
#...
main.dart
import 'package:flutter/material.dart';
import 'src/app.dart';
void main() => runApp(App());
src/app.dart
import 'package:flutter/material.dart';
import 'screens/login_screen.dart';
import 'blocs/provider.dart';
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider(
child: MaterialApp(
title: 'Login',
home: Scaffold(
appBar: AppBar(
title: Text('LoginForm'),
),
body: LoginScreen(),
),
),
);
}
}
src/screens/login_screen.dart
import 'package:flutter/material.dart';
import '../blocs/bloc.dart';
import '../blocs/provider.dart';
class LoginScreen extends StatefulWidget {
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
@override
Widget build(BuildContext context) {
final bloc = Provider.of(context);
return Container(
margin: EdgeInsets.all(8.0),
child: Form(child:
Column(children: <Widget>[
fieldEmail(bloc),
fieldPassword(bloc),
_submit(bloc),
],
),
),
);
}
Widget fieldEmail(Bloc bloc) {
return StreamBuilder(
stream: bloc.email,
builder: (context, snapshot) {
return TextField(
onChanged: bloc.changeEmail,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
hintText: 'useanem@domain.com',
errorText: snapshot.error,
),
);
}
);
}
Widget fieldPassword(Bloc bloc) {
return StreamBuilder(
stream: bloc.password,
builder: (context, snapshot) {
return TextField(
onChanged: bloc.changePassword,
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
hintText: 'over 3 charactor',
errorText: snapshot.error,
),
);
}
);
}
Widget _submit(Bloc bloc) {
return StreamBuilder(
stream: bloc.submitValid,
builder: (context, snapshot) {
return RaisedButton(
color: Colors.blue,
child: Text('Submit', style: TextStyle(color: Colors.white),),
// AsyncSnapshot <T> Class
// https://api.flutter.dev/flutter/widgets/AsyncSnapshot-class.html
onPressed: snapshot.hasError
? null
: (){
print('onPressed Submit');
},
);
}
);
}
}
src/blocs/bloc.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'validators.dart';
import 'package:rxdart/rxdart.dart';
class Bloc extends Object with Validators {
final _email = StreamController<String>.broadcast();
final _passwd = StreamController<String>.broadcast();
Stream<String> get email => _email.stream.transform(validatorEmail);
Stream<String> get password => _passwd.stream.transform(validatorPassword);
// https://pub.dev/documentation/rxdart/latest/rx/CombineLatestStream-class.html
// https://pub.dev/documentation/rxdart/latest/rx/CombineLatestStream/combine2.html
// Stream<bool> get submitValid => Observable.combineLatest2(email, password, (e, p)=>true);
Stream<bool> get submitValid => CombineLatestStream([email, password], (_)=>true);
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _passwd.sink.add;
dispose() {
_email.close();
_passwd.close();
}
}
src/blocs/provider.dart
import 'package:flutter/material.dart';
import 'bloc.dart';
class Provider extends InheritedWidget {
final bloc = Bloc();
Provider({key, Widget child}) : super(key: key, child: child);
// @override
// bool updateShuldNotify(_) => true;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
/*{
throw UnimplementedError();
}*/
static Bloc of(BuildContext context) {
// ignore: deprecated_member_use
// return (context.inheritFromWidgetOfExactType(Provider) as Provider).bloc;
// https://stackoverflow.com/a/59304297
return (context.dependOnInheritedWidgetOfExactType<Provider>()).bloc;
}
}
src/blocs/validators.dart
import 'dart:async';
class Validators {
final validatorEmail = StreamTransformer<String, String>.fromHandlers(
handleData: (String email, sink) {
if( email.contains('@') ){
sink.add(email);
} else {
sink.addError('Enter a valid email');
}
}
);
final validatorPassword = StreamTransformer<String, String>.fromHandlers(
handleData: (String passwd, sink) {
if( passwd.length >= 3 ) {
sink.add(passwd);
} else {
sink.addError('password must be at leat 3 characters');
}
}
);
}
Flutter State
- Flutter BLoC
- Flutter BLoC, Single Global Instance
- Flutter BLoC, Scoped Instances
- Flutter BLoC, RxDart combineLatestStream
- Flutter BLoC, RxDart combineLatestStream BehaviorSubject On Submit
반응형
'lang > dart' 카테고리의 다른 글
Flutter Animation (0) | 2020.09.21 |
---|---|
Flutter BLoC, RxDart combineLatestStream BehaviorSubject On Submit (0) | 2020.09.18 |
Flutter BLoC, Scoped Instances (0) | 2020.09.16 |
Flutter BLoC, Single Global Instance (0) | 2020.09.15 |
Flutter BLoC (0) | 2020.09.14 |