[英]flutter - bloc - how can I use FutureBuilder in my Ui to properly implement Bloc Architecture
I am newbie to flutter and Bloc architecture and I am trying to use Bloc for my login functionality.我是 flutter 和 Bloc 架构的新手,我正在尝试将 Bloc 用于我的登录功能。 I am trying to make a call to a function in my Bloc file, but I do not know how to do that.我正在尝试调用我的 Bloc 文件中的函数,但我不知道该怎么做。 also I would be glad if you could help me to see if there is any other problems in my use of Bloc.如果您能帮我看看我在使用 Bloc 时是否还有其他问题,我也会很高兴。 here is the code of my Ui:这是我的 Ui 的代码:
MaterialButton(
color: Colors.deepPurple,
minWidth: screenAwareSize(500, context),
onPressed: () {
_submitForm(authBloc, user, pass);
},
void _submitForm(AuthBloc authBloc, String user, String pass) async {
formKey.currentState.save();
if (formKey.currentState.validate()) {
var response = await authBloc.login(user, pass);
//when I print(response) it shows null
}
}
here is my bloc class:这是我的集团班级:
class AuthBloc extends MainBloc {
final Repo _repo = Repo();
PublishSubject<Future<UserModel>> _authController = new PublishSubject<Future<UserModel>>();
Observable<Future<UserModel>> get auth => _authController.stream;
login(String user, String pass) async {
Future<UserModel> item = await _repo.login(user, pass);
_authController.sink.add(item);
}
dispose() {
_authController.close();
}
}
AuthBloc authBloc = new AuthBloc();
and here is my API class:这是我的 API 类:
class API{
Future<UserModel> login(String user, String pass) async {
var response =
await client.get(base_url + "login.php?user=${user}&pass=${pass}");
return UserModel.fromJSON(json.decode(response.body));
}}
here is my repo class:这是我的回购类:
class Repo {
final API api = new API();
login(String user, String pass) async => await api.login(user, pass);}
I will try to explain first what BLOC components should do as short as possible (and as trivial as possible).我将首先尝试解释 BLOC 组件应该做什么,尽可能短(并且尽可能琐碎)。
You can have other components too, based on what your app does, like:根据您的应用程序的功能,您也可以拥有其他组件,例如:
Now, I would suggest to use the BLOC pattern with Dependency Injection too, without it is kind of useless.现在,我建议也将 BLOC 模式与依赖注入一起使用,否则它是无用的。 With DI, you can mock all components till UI and it would be very easy to unit test all your code.使用 DI,您可以模拟所有组件直到 UI,并且可以很容易地对所有代码进行单元测试。
Also, I think there's no point to mix RxDart(library) with Streams/Future(dart equivalent of RxDart lib).另外,我认为将 RxDart(库)与 Streams/Future(dart 等效于 RxDart 库)混合使用是没有意义的。 For start, I would suggest to use only one of it and based on your code snippet, I would suggest to have better look on how to use Rx overall.首先,我建议只使用其中一个,并且根据您的代码片段,我建议更好地了解如何使用 Rx。
So, below you have a small code snippet on how I would use the block patter to do a login(it would be nice to check the code comments too :) ).所以,下面你有一个关于我将如何使用块模式进行登录的小代码片段(检查代码注释也很好:))。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class TheUIScreen extends StatefulWidget {
@override
_TheUIScreenState createState() => _TheUIScreenState();
}
class _TheUIScreenState extends State<TheUIScreen> {
//TODO: for repo, block, networking, we used dependecy injection, here we have to create and init all the dependecies;
TheAuthBlock _block;
@override
void initState() {
super.initState();
TheAuthAPI api = TheAuthAPI();
TheAuthRepo repo =
TheAuthRepo(theAuthAPI: api); // we could also do repo = TheAuthRepo();
_block =
TheAuthBlock(repo: repo); // we could also do _block = TheAuthBlock();
}
@override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(onPressed: () {
_block.loginUser("test", "test").then((actualUser) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return TestRoute(); // or do whatever action you need, the user is logged in
}));
}).catchError((error) {
//show error, something went wrong at login;
});
}),
);
}
}
class TheAuthBlock {
final TheAuthRepo repo;
TheAuthBlock({this.repo = const TheAuthRepo()});
Future<UserModel> loginUser(String email, String password) {
return repo.login(email, password).then((userModel) {
//TODO: here we decide HOW to display the user, you might want to transfor the UserModel into a model that's used only for UI.
//In any way, here you should do all the processing, the UI only should only display the data, not manipulate it.
});
}
}
class TheAuthRepo {
final TheAuthAPI theAuthAPI;
const TheAuthRepo(
{this.theAuthAPI =
const TheAuthAPI()}); // THIS would be the default constructor but it will alow us to test it using unit tests.
Future<UserModel> login(String email, String password) {
//TODO: here you could also check if the user is already logged in and send the current user as a response
if (email.isNotEmpty && password.isNotEmpty) {
return theAuthAPI.login(email, password).then((userModel) {
//TODO: you can do extra processing here before returning the data to the block;
});
} else {
return Future.error(
"Well you can't login with empty ddata"); // TODO: you can return differetn errors for email or pwd;
}
}
}
class TheAuthAPI {
final String url;
const TheAuthAPI({this.url = "https://my.cool.api/login"});
Future<UserModel> login(String email, String pwd) {
// TODO: note you return a future from this method since the login will return only once (like almost all http calls)
Map<String, String> headers = Map(); // TODO: set any headers you need here
Map<String, String> body = {
"email": email,
"pwd": pwd
}; // TODO: change the body acordingly
return http.post("THE URL", headers: headers, body: body).then((response) {
//TODO: parse response here and return it
return UserModel("test",
"test"); // this should be generated from the response not like this
});
}
}
class UserModel {
final String email;
UserModel(this.email, this.pass);
final String pass;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.