问题描述
我是Flutter和Bloc架构的新手,我正在尝试将Bloc用于我的登录功能。我正在尝试调用Bloc文件中的函数,但是我不知道该怎么做。如果您能帮助我看看我在使用Bloc时是否还有其他问题,我也将很高兴。
这是我的Ui代码:
I am newbie to flutter and Bloc architecture and I am trying to use Bloc for my login functionality. I am trying to make a call to a function in my Bloc file, but I do not know how to do that. also I would be glad if you could help me to see if there is any other problems in my use of Bloc.here is the code of my 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
}
}
这是我的集团类:
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();
这是我的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));
}}
这是我的回购类别:
class Repo {
final API api = new API();
login(String user, String pass) async => await api.login(user, pass);}
推荐答案
首先,我将尝试解释BLOC组件应该做的越短越好(并且尽可能琐碎)。
I will try to explain first what BLOC components should do as short as possible (and as trivial as possible).
- UI屏幕-显然显示向用户显示数据
- BLOC(或ViewModel)-决定如何向用户显示数据,是否使文本加粗,是否显示错误,是否转到下一个屏幕
- 回购-决定向用户显示哪些数据(我们是否从db中显示内容,是否从API中获取内容,是否显示红色产品?)
您也可以根据应用程序的功能来使用其他组件,例如:
You can have other components too, based on what your app does, like:
- 网络-执行API请求并将响应转换为模型,这只能从存储库访问,并且该组件唯一要做的就是从存储库接收数据(标头,正文,URL),并且以模型的形式返回数据以回购(您可以将代码检查为低)。
- 数据库-对数据库执行CRUD操作,只能从仓库中访问。
- 传感器-从本机传感器读取数据,仅可访问
现在,我建议也将BLOC模式与Dependency Injection一起使用,如果没有它是没有用的。使用DI,您可以在UI之前模拟所有组件,并且可以轻松地对所有代码进行单元测试。
Now, I would suggest to use the BLOC pattern with Dependency Injection too, without it is kind of useless. With DI, you can mock all components till UI and it would be very easy to unit test all your code.
此外,我认为没有必要混合RxDart(library )和Streams / Future(相当于RxDart库的镖)。首先,我建议只使用其中之一,并根据您的代码片段,建议您更好地了解如何整体使用Rx。
Also, I think there's no point to mix RxDart(library) with Streams/Future(dart equivalent of RxDart lib). 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.
因此,下面是关于如何使用块模式进行登录的小代码段(也可以检查代码注释:))。
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;
}
这篇关于flutter-bloc-如何在Ui中使用FutureBuilder正确实现Bloc Architecture的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!