I have a ConsumerStatefulWidget and a ConsumerState class. I want to access my StateNotifierProvider inside the ConsumerState class but I am getting an error on ref saying The instance member 'ref' can't be accessed in an initializer.
I have been working on this for quite a while and I am learning a lot but I thought I could access ref inside the ConsumerState class.
Here is my code:
// Create the global provider
final globalProvider = StateNotifierProvider<GlobalsNotifier, Globals>(
(ref) => GlobalsNotifier(Globals(
currentUid: '',
currentUEmail: '',
userDocumentId: '',
companyId: '',
mlsId: '',
currentTrxnId: '',
currentCompanyName: '',
currentCompanyState: '',
currentUserId: '',
currentUserName: '',
currentUserState: '',
selectedCompany: '',
selectedState: '',
selectedTrxnState: '',
selectedUser: '',
selectedUserState: '',
targetScreen: '',
newCompany: true,
newEvent: true,
newTrxn: true,
newUser: true)));
class LoginScreen extends ConsumerStatefulWidget {
static const String id = 'login_screen';
@override
ConsumerState<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends ConsumerState<LoginScreen> {
bool showSpinner = false;
final _auth = FirebaseAuth.instance;
final globals = ref.read(globalProvider); <<<< Access ref here
late String email;
late String password;
getCurrentAgencyName() async {
final DocumentSnapshot _currentAgentProfile =
await agentsRef.doc(ref.watch(globalProvider.currentUid)).get();
if (_currentAgentProfile != null) {
ref.read(GlobalsProvider.companyId.notifier).state =
_currentAgentProfile.get('agencyId');
ref.read(GlobalsProvider.currentUserStateProvider.notifier).state =
_currentAgentProfile.get('state');
ref.read(GlobalsProvider.mlsId.notifier).state =
_currentAgentProfile.get('mlsId');
}
final DocumentSnapshot _currentAgencyProfile =
await agencyRef.doc(ref.watch(GlobalsProvider.companyId)).get();
if (_currentAgencyProfile != null) {
ref.read(GlobalsProvider.currentCompanyState.notifier).state =
_currentAgencyProfile.get('state');
ref.read(GlobalsProvider.currentCompanyName.notifier).state =
_currentAgencyProfile.get('name');
}
}
@override
Widget build(BuildContext context) {
bool loginFail = false;
String errorMessage = "";
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Row(
mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Image.asset('assets/images/logo.png',
// fit: BoxFit.cover, height: 56),
// ],
),
),
resizeToAvoidBottomInset: false, // This fixes the keyboard white space
body: SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Text(
'Login',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w900,
fontSize: 40.0,
),
textAlign: TextAlign.center,
),
const SizedBox(
height: 48.0,
),
TextField(
autofocus: true,
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
email = value;
},
decoration: InputDecoration(
labelText: 'Email',
errorText: loginFail ? 'incorrect email' : null,
),
),
const SizedBox(
height: 8.0,
),
TextField(
obscureText: true,
textAlign: TextAlign.center,
onChanged: (value) {
password = value;
},
decoration: InputDecoration(
labelText: 'Password',
errorText: loginFail ? 'incorrect passwowrd' : null,
),
),
TextButton(
child: const Text(
'Login',
style: TextStyle(fontSize: 15),
),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ResetPasswordScreen())),
),
TextButton(
child: const Text(
'Forgot Password',
style: TextStyle(fontSize: 15),
),
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
UserCredential userCredential =
await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (userCredential != null) {
// Set the global state
ref.read(GlobalsProvider.currentUid.notifier).state =
_auth.currentUser!.uid;
ref.read(GlobalsProvider.currentUserId.notifier).state =
_auth.currentUser!.uid;
ref.read(GlobalsProvider.currentUEmail.notifier).state =
_auth.currentUser!.email;
ref.read(GlobalsProvider.targetScreen.notifier).state =
0;
await getCurrentAgencyName();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MainScreen()),
);
} else {
setState(() {
loginFail = true;
});
}
setState(() {
showSpinner = false;
});
} on FirebaseAuthException catch (error) {
switch (error.code) {
case "ERROR_INVALID_EMAIL":
case "invalid-email":
errorMessage =
"Your email address appears to be malformed.";
break;
case "email-already-in-use":
errorMessage = "Email is already in use.";
break;
case "ERROR_WRONG_PASSWORD":
case "wrong-password":
errorMessage = "Your password is wrong.";
break;
case "ERROR_USER_NOT_FOUND":
case "user-not-found":
errorMessage = "User with this email doesn't exist.";
break;
case "ERROR_USER_DISABLED":
case "user-disabled":
errorMessage =
"User with this email has been disabled.";
break;
case "ERROR_TOO_MANY_REQUESTS":
case "too-many-requests":
errorMessage = "Too many requests. Try again later.";
break;
case "ERROR_OPERATION_NOT_ALLOWED":
case "operation-not-allowed":
errorMessage =
"Signing in with Email and Password is not enabled.";
break;
default:
errorMessage =
"An undefined Error happened. Please try again.";
}
if (errorMessage != null && errorMessage != "") {
ScaffoldMessenger.of(context).showSnackBar(
(SnackBar(content: Text(errorMessage))));
}
}
}),
RoundedButton(
title: 'Log In',
colour: Colors.lightBlueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
UserCredential userCredential =
await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (userCredential != null) {
ref.read(GlobalsProvider.currentUid.notifier).state =
_auth.currentUser!.uid;
ref.read(GlobalsProvider.currentUserId.notifier).state =
_auth.currentUser!.uid;
ref.read(GlobalsProvider.currentUEmail.notifier).state =
_auth.currentUser!.email;
ref.read(GlobalsProvider.targetScreen.notifier).state =
0;
await getCurrentAgencyName();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MainScreen()),
);
} else {
setState(() {
loginFail = true;
});
}
setState(() {
showSpinner = false;
});
} on FirebaseAuthException catch (error) {
switch (error.code) {
case "ERROR_INVALID_EMAIL":
case "invalid-email":
errorMessage =
"Your email address appears to be malformed.";
break;
case "email-already-in-use":
errorMessage = "Email is already in use.";
break;
case "ERROR_WRONG_PASSWORD":
case "wrong-password":
errorMessage = "Your password is wrong.";
break;
case "ERROR_USER_NOT_FOUND":
case "user-not-found":
errorMessage = "User with this email doesn't exist.";
break;
case "ERROR_USER_DISABLED":
case "user-disabled":
errorMessage =
"User with this email has been disabled.";
break;
case "ERROR_TOO_MANY_REQUESTS":
case "too-many-requests":
errorMessage = "Too many requests. Try again later.";
break;
case "ERROR_OPERATION_NOT_ALLOWED":
case "operation-not-allowed":
errorMessage =
"Signing in with Email and Password is not enabled.";
break;
default:
errorMessage =
"An undefined Error happened. Please try again.";
}
if (errorMessage != null && errorMessage != "") {
ScaffoldMessenger.of(context).showSnackBar(
(SnackBar(content: Text(errorMessage))));
}
}
}),
const SizedBox(
height: 100.0,
),
TextButton(
child: const Text(
'New User? Create Account',
style: TextStyle(fontSize: 15, color: Colors.blue),
),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => UserRegisterScreen())),
),
],
),
),
),
);
}
}
Am I using the correct class or should I be using something else in place of the StatefulWidget class?
I am obviously not referencing ref in the correct place so where should I access it so I can use it throughout the code?
Thanks
ref
is a property of ConsumerState (and its subclasses). As a property, you cannot use it in the initializer of another property, similar to the way that:
int f = 5;
int g = f + 2; // not allowed
is not allowed. All initializers are presumed to execute "in a silo", not seeing any neighboring values.
The proper response is to declare the property as late
, and initialize it in an overridden initState
, where the remaining properties will be available to use.