问题
I am trying to implement custom logout solution for my application, where no matter where user currently is, once the Logout button
is clicked, app will navigate back to Login page
.
My idea was, that instead of listening on every component for state changes, I would have one single listener on a master component -> MyApp
.
For the sake of simplicity, I have stripped down items to bare minimum. Here is how my Profile class could look like:
class Profile with ChangeNotifier {
bool _isAuthentificated = false;
bool get isAuthentificated => _isAuthentificated;
set isAuthentificated(bool newVal) {
_isAuthentificated = newVal;
notifyListeners();
}
}
Now, under Main
, I have registered this provider as following:
void main() => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => Profile(),
)
],
child: MyApp(),
),
);
And finally MyApp
component:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return Consumer<Profile>(
builder: (context, profile, _) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Color.fromARGB(255, 0, 121, 107),
accentColor: Color.fromARGB(255, 255, 87, 34),
),
home: buildBasePage(context, profile),
);
},
);
}
Widget buildBasePage(BuildContext context, Profile currentProfile) {
return !currentProfile.isAuthentificated
? LoginComponent()
: MyHomePage(title: 'Flutter Demo Home Page test');
}
}
My idea was, that as MyApp
component is the master, I should be able to create a consumer, which would be notified if current user is authentificated, and would respond accordingly.
What happens is, that when I am in e.g. MyHomePage
component and I click Logout()
method which looks like following:
void _logout() {
Provider.of<Profile>(context, listen: false).isAuthentificated = false;
}
I would be expecting that upon changing property, the initial MyApp
component would react and generate LoginPage
; which is not the case. I have tried changing from Consumer
to Provider.of<Profile>(context, listen: false)
yet with the same result.
What do I need to do in order for this concept to work? Is it even correct to do it this way?
I mean I could surely update my Profile
class in a way, that I add the following method:
logout(BuildContext context) {
_isAuthentificated = false;
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginComponent()));
}
And then simply call Provider.of<Profile>(context, listen: false).logout()
, however I thought that Provider package was designed for this...or am I missing something?
Any help in respect to this matter would be more than appreciated.
回答1:
I don't know why it wasn't working for you. Here is a complete example I built based on your description. It works!
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Profile with ChangeNotifier {
bool _isAuthentificated = false;
bool get isAuthentificated {
return this._isAuthentificated;
}
set isAuthentificated(bool newVal) {
this._isAuthentificated = newVal;
this.notifyListeners();
}
}
void main() {
return runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<Profile>(
create: (final BuildContext context) {
return Profile();
},
)
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(final BuildContext context) {
return Consumer<Profile>(
builder: (final BuildContext context, final Profile profile, final Widget child) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: profile.isAuthentificated ? MyHomePage() : MyLoginPage(),
);
},
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(final BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Home [Auth Protected]")),
body: Center(
child: RaisedButton(
child: const Text("Logout"),
onPressed: () {
final Profile profile = Provider.of<Profile>(context, listen: false);
profile.isAuthentificated = false;
},
),
),
);
}
}
class MyLoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Login")),
body: Center(
child: RaisedButton(
child: const Text("Login"),
onPressed: () {
final Profile profile = Provider.of<Profile>(context, listen: false);
profile.isAuthentificated = true;
},
),
),
);
}
}
回答2:
You don't need to pass listen:false
, instead simply call
Provider.of<Profile>(context).logout()
So your Profile class would look like
class Profile with ChangeNotifier {
bool isAuthentificated = false;
logout() {
isAuthentificated = false;
notifyListeners();
}
}
来源:https://stackoverflow.com/questions/60108556/flutter-provider-state-management-logout-concept