问题描述
我正在尝试使用 MOBX 在两个字段(电子邮件和密码)中进行验证,并且正在 compuntig 中计算两个函数的结果。名为formIsValid,但mobX向我返回了此错误:一个构建函数返回了null。 相关的引起错误的小部件是 观察者
我尝试用不同的方式来做,但我做不到,而且我的电子邮件观察对象 emailErrorLabel 和 passwordErrorLabel 不会影响 TextTormField errorText。
import 'package:covid_app/app/service/firebase/firebase_auth.dart';
import 'package:covid_app/app/service/firebase/firebase_auth_impl.dart';
import 'package:covid_app/app/ui/home/home_page.dart';
import 'package:Flutter/material.dart';
import 'package:mobx/mobx.dart';
part 'login_viewmodel.g.dart';
class Loginviewmodel = LoginviewmodelBase with _$Loginviewmodel;
abstract class LoginviewmodelBase with Store {
@observable
String email = "";
@observable
String password = "";
@observable
bool error = false;
@observable
bool emailErrorLabel = false;
@observable
bool passwordErrorLabel = false;
final _auth = Auth();
@action
changeEmail(String newEmail) => email = newEmail;
@action
changePassword(String newPassword) => password = newPassword;
@action
setHasErrorOnEmail(bool value) => emailErrorLabel = value;
@action
setHasErrorOnPassword(bool value) => passwordErrorLabel = value;
bool emailIsValid() {
if (email.isNotEmpty && email.contains("@")) {
return true;
} else {
setHasErrorOnEmail(true);
return false;
}
}
bool passwordisValid() {
if (password.isNotEmpty || password.length >= 8) {
return true;
} else {
setHasErrorOnPassword(true);
return false;
}
}
@computed
bool get formIsValid {
return emailIsValid() && passwordisValid();
}
@action
Future<void> firebaseLogin(dynamic context) async {
try {
if (email.isNotEmpty && password.isNotEmpty) {
var userId;
await _auth.signIn(email,password).then((value) => userId = value);
userId.length > 0 ? homeNavigator(context) : error = true;
} else {
error = true;
}
} catch (Exception) {
error = true;
print("Login Error: $Exception");
}
}
void homeNavigator(context) {
Navigator.push(
context,MaterialPageRoute(builder: (context) => HomePage()));
}
}
import 'package:covid_app/app/ui/login/login_viewmodel.dart';
import 'package:covid_app/app/widgets/KeyboardHideable.dart';
import 'package:covid_app/core/constants/colors.dart';
import 'package:covid_app/core/constants/dimens.dart';
import 'package:covid_app/core/constants/string.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:Flutter/material.dart';
import 'package:Flutter_mobx/Flutter_mobx.dart';
import '../../widgets/button_component.dart';
import 'widgets/text_form_field_component.dart';
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
var vm = Loginviewmodel();
var value = zero;
var valueTextFields = sixtyEight;
TextEditingController controllerEmail = TextEditingController();
TextEditingController controllerPassword = TextEditingController();
void animatedtest() async {
Future.delayed(Duration(seconds: 0),() {
setState(() {
value = sixtyEight;
valueTextFields = zero;
});
});
}
@override
void initState() {
super.initState();
animatedtest();
}
@override
Widget build(BuildContext context) {
return KeyboardHideable(
child: Scaffold(
backgroundColor: darkPrimaryColor,body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,child: SafeArea(
child: Center(
child: Padding(
padding: const EdgeInsets.all(sixteen),child: Column(
mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
Expanded(
child: Card(
elevation: twelve,shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(twentyFour)),),child: Padding(
padding: const EdgeInsets.all(thirtyTwo),child: Column(
mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
Spacer(),Expanded(
flex: 8,child: AnimatedContainer(
margin: EdgeInsets.only(bottom: value),duration: Duration(seconds: 1),child: Image.asset(
"assets/images/logo_covid_app.png")),Expanded(
flex: 7,child: AnimatedContainer(
margin:
EdgeInsets.only(top: valueTextFields),child: Column(
children: <Widget>[
Expanded(
flex: 2,child: Observer(
builder: (_) =>
TextFormFieldComponent(
emailHintText,false,controllerEmail,vm.changeEmail,vm.emailErrorLabel,emailErrorLabel),Expanded(
flex: 2,child: Observer(builder: (_) {
return TextFormFieldComponent(
passwordHintText,true,controllerPassword,vm.changePassword,passwordErrorLabel);
}),],SizedBox(
height: twentyEight,Expanded(
flex: 2,child: Observer(
builder: (_) => ButtonComponent(
title: loginButtonLabel,fillColor: rosePrimaryColor,textColor: Colors.white,loginFun: vm.formIsValid
? () => vm.firebaseLogin(context)
: null,SizedBox(
height: twenty,child: ButtonComponent(
title: registerButtonLabel,fillColor: darkPrimaryColor,loginFun: () {}),Spacer()
],);
}
}
我的TextFormField组件:
import 'package:covid_app/core/constants/colors.dart';
import 'package:covid_app/core/constants/dimens.dart';
import 'package:Flutter/material.dart';
// ignore: must_be_immutable
class TextFormFieldComponent extends StatefulWidget {
String hintText;
bool hideText;
TextEditingController genericControler;
bool genericValidation;
String errorMessage;
Function onChangedGeneric;
TextFormFieldComponent(this.hintText,this.hideText,this.genericControler,this.onChangedGeneric,this.genericValidation,this.errorMessage);
@override
_TextFormFieldComponentState createState() => _TextFormFieldComponentState();
}
class _TextFormFieldComponentState extends State<TextFormFieldComponent> {
@override
Widget build(BuildContext context) {
return Theme(
data:
ThemeData(cursorColor: rosePrimaryColor,hintColor: darkPrimaryColor),child: TextFormField(
onChanged: widget.onChangedGeneric,controller: widget.genericControler,obscureText: widget.hideText,decoration: Inputdecoration(
hintText: widget.hintText,errorText: widget.genericValidation == true ? widget.errorMessage : null,border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(twentyFour)),enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(twentyFour)),borderSide: BorderSide(width: two,color: darkPrimaryColor),focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(twentyFour)),borderSide: BorderSide(
width: two,color: rosePrimaryColor,);
}
}
我的按钮组件:
import 'package:covid_app/core/constants/colors.dart';
import 'package:covid_app/core/constants/dimens.dart';
import 'package:Flutter/material.dart';
// ignore: must_be_immutable
class ButtonComponent extends StatefulWidget {
var title;
var fillColor;
var textColor;
Function loginFun;
ButtonComponent({Key key,this.title,this.fillColor,this.textColor,this.loginFun});
@override
_ButtonComponentState createState() => _ButtonComponentState();
}
class _ButtonComponentState extends State<ButtonComponent> {
@override
Widget build(BuildContext context) {
return Container(
width: hundredSeventyTwo,height: fortyFour,child: RaisedButton(
disabledColor: Colors.grey,shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
twentyFour,onpressed: widget.loginFun,color: widget.fillColor,child: Text(
widget.title,style: TextStyle(
color: widget.textColor,);
}
}
打印错误:https://i.stack.imgur.com/UmQd5.png / https://i.stack.imgur.com/K13rN.png
解决方法
好吧,错误说明了一切,真的没什么可补充的。
在formIsValid
计算出的内部,您调用2个函数,这些函数可能会修改emailErrorLabel
或passwordErrorLabel
,并且由于它们既observable
且在同一渲染中使用,因此不允许。
computed
应该是没有副作用的纯函数,它应该仅从其他computed
,observable
或常量值中得出一些值。