来自完整开发人员指南课程 Udemy 165 的 Flutter Bloc 模式问题
Posted
技术标签:
【中文标题】来自完整开发人员指南课程 Udemy 165 的 Flutter Bloc 模式问题【英文标题】:Flutter Bloc pattern question from The complete developers guide course Udemy 165 【发布时间】:2021-12-20 02:04:11 【问题描述】:我对 Udemy 的这门课程有疑问,我试图在 Flutter 中设置 Bloc 模式以进行身份验证。问题是,当我从 StreamBuilder 的 snapshot.error 中键入所需的“@”时,我从一开始就得到了一个空值。它已设置好,所以我应该会收到一条错误消息,直到我输入“@”,然后该消息就会消失。我有三个相关文件:loginscreen、bloc 和验证器。你们认为这里会出现什么问题?
登录界面:
class LoginScreen extends StatelessWidget
@override
Widget build(context)
return Container(
margin: EdgeInsets.all(20.0),
child: Column(
children: [
emailField(),
passwordField(),
//const SizedBox(height: 25.0),
Container(margin: const EdgeInsets.only(top: 25.0)),
submitButton(),
],
),
);
Widget emailField()
//Listener for streams rebuilds builder function when found
return StreamBuilder(
stream: bloc.email,
//snapshot contains the value from the stream
builder: (context, AsyncSnapshot<String>? snapshot)
return TextField(
onChanged: (newValue)
print(newValue);
bloc.changeEmail(newValue);
,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'you@example.com',
labelText: 'Email Address',
//This is null for some reason. Something is not right here
//First it shows error because no @ and when pressed I get null
errorText: snapshot!.error.toString(),
),
);
);
Bloc:
class Bloc with Validators
//We are working with Strings in the Streamcontrollers (marked with String type)
final _email = StreamController<String>();
final _password = StreamController<String>();
//Annotation with generic type in front. Not required though
// Add data to stream (access to stream)
// Apply the validation transform created
Stream<String> get email => _email.stream.transform(validateEmail);
Stream<String> get password => _password.stream.transform(validatePassword);
// Change data (access to sink)
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
dispose()
_email.close();
_password.close();
final bloc = Bloc();
Validators:
class Validators
final validateEmail =
StreamTransformer<String, String>.fromHandlers(handleData: (email, sink)
if (email.contains('@'))
sink.add(email);
else
sink.addError('Enter a valid email!');
);
final validatePassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink)
if (password.length > 7)
sink.add(password);
else
sink.addError('You must be at least 8 characters!');
);
更改为:
errorText: 快照?.error?.toString() ??快照?.数据,
【问题讨论】:
【参考方案1】:你总是在这里阅读流的错误:
errorText: snapshot!.error.toString(),
但你只在这个 else 中添加错误:
if (email.contains('@'))
sink.add(email);
else
sink.addError('Enter a valid email!');
您可以尝试替换此值的读取方式:
//This is null for some reason. Something is not right here
//First it shows error because no @ and when pressed I get null
errorText: snapshot?.error?.toString() ?? snapshot?.data,
这样,如果没有错误,errorText
就会得到流的数据。
更新: 如果你想让这个消息在 @ 被插入后完全消失,你可以先看看 errorText 是如何工作的。来自 Flutter 的 InptuDecorator 源码:
/// Text that appears below the [InputDecorator.child] and the border.
///
/// If non-null, the border's color animates to red and the [helperText] is
/// not shown.
///
/// In a [TextFormField], this is overridden by the value returned from
/// [TextFormField.validator], if that is not null.
final String? errorText;
因此,如果您不向其传递字符串,该消息将被隐藏。这段代码发生了什么:
errorText: snapshot!.error.toString(),
是这样的:null.toString();
。 Dart 可以并将 null 解析为字符串,并将其转换为以 null
为内容的字符串。
为了解决这个问题,我们在错误后添加一个?
标记,如下所示: snapshot?.error?.toString(),
。现在,toString()
只会在 error
不为空时被调用。
提示:一定要探索您正在使用的小部件的源代码。他们被广泛评论,你可以比谷歌随机的东西更快地获取信息?
【讨论】:
感谢您的回复 Tales Barreto!是的,我尝试了该解决方案并且它有效,但仍有一个问题是即使 @ 存在,文本也是红色而不是蓝色(如错误文本)。我猜那是因为错误文本为空,他从那里读取了 snapshot.data。 嘿!我刚刚更新了我的答案;-) 是的,感谢您的洞察力!我已阅读该文档,我认为问题在于,当您开始键入时,它会在按下 @ 后转到 else(错误消息已设置),而错误变为 null(但仍处于错误状态)并且快照?.data 已设置到 errorText 并且当我键入每个字符时,现在可以看到每个字符,直到我删除 @ 并且再次看到错误消息(如果我不全部删除,则始终为红色)。这让我有点难以理解!以上是关于来自完整开发人员指南课程 Udemy 165 的 Flutter Bloc 模式问题的主要内容,如果未能解决你的问题,请参考以下文章