在我使用 Flutter 構建的應用程式中,我使用提供程式包向我的應用程式添加狀態管理。此外,我使用共享首選項包來跟蹤我的用戶的登錄狀態(基于令牌)。該應用程式使用一個使用Sanctum的 Laravel API 。
一切都按預期作業。但是,在注銷用戶并使用其他用戶重新登錄后,會導致顯示先前用戶的資料。我注意到舊用戶的令牌一直保留在提供者中,這會導致舊資料加載。
main.dart
Future main() async {
await dotenv.load(fileName: ".env");
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => AuthProvider(),
child: Consumer<AuthProvider>(builder: (context, authProvider, child) {
return MultiProvider(
providers: [
ChangeNotifierProvider<CategoryProvider>(
create: (context) => CategoryProvider(authProvider)),
ChangeNotifierProvider<TransactionProvider>(
create: (context) => TransactionProvider(authProvider)),
ChangeNotifierProvider<ProfileProvider>(
create: (context) => ProfileProvider(authProvider))
],
child: MaterialApp(
title: 'Flutter App',
routes: {
'/': (context) {
final authProvider = Provider.of<AuthProvider>(context);
return authProvider.isAuthenticated ? Home() : Login();
},
'/login': (context) => Login(),
'/register': (context) => Register(),
'/profile': (context) => Profile(),
'/categories': (context) => Categories(),
},
));
}));
}
}
鑒于上面的例子,我期待對我的 AuthProvider 進行任何更改,以重建在 Consumer 小部件中列出的提供者。
auth_provider.dart
class AuthProvider extends ChangeNotifier {
bool isAuthenticated = false;
late String token;
AuthProvider() {
init();
}
Future<void> init() async {
this.token = await getToken();
if (this.token.isNotEmpty) {
this.isAuthenticated = true;
}
ApiService apiService = ApiService(this.token);
notifyListeners();
}
ApiService apiService = ApiService('');
Future<void> register(String name, String email, String password,
String passwordConfirm, String deviceName) async {
this.token = await apiService.register(name, email, password, passwordConfirm, deviceName);
setToken(this.token);
this.isAuthenticated = true;
notifyListeners();
}
Future<void> login(String email, String password, String deviceName) async {
this.token = await apiService.login(email, password, deviceName);
setToken(this.token);
this.isAuthenticated = true;
notifyListeners();
}
Future<void> logout() async {
this.token = '';
this.isAuthenticated = false;
setToken(this.token);
final prefs = await SharedPreferences.getInstance();
prefs.clear();
notifyListeners();
}
Future<void> setToken(token) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString('token', token);
}
Future<String> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('token') ?? '';
}
}
在logout()函式中,我正在清除令牌。
category_provider.dart
class CategoryProvider extends ChangeNotifier {
List<Category> categories = [];
late ApiService apiService;
late AuthProvider authProvider;
CategoryProvider(AuthProvider authProvider) {
this.authProvider = authProvider;
this.apiService = ApiService(authProvider.token);
init();
}
Future init() async {
categories = await apiService.fetchCategories();
notifyListeners();
}
Future<void> addCategory(String name) async {
try {
Category addedCategory = await apiService.addCategory(name);
categories.add(addedCategory);
notifyListeners();
} catch (Exception) {
print(Exception);
}
}
// omitted functions
}
The ApiService is a class that receives the passed token and does API calls for the providers.
api.dart
class ApiService {
late String token;
ApiService(String token) {
this.token = token;
}
final String baseUrl = dotenv.env['APP_URL'].toString() '/api/';
Future<List<Category>> fetchCategories() async {
http.Response response =
await http.get(Uri.parse(baseUrl 'categories'), headers: {
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.acceptHeader: 'application/json',
HttpHeaders.authorizationHeader: 'Bearer $token',
});
List categories = jsonDecode(response.body)['data'];
return categories.map((category) => Category.fromJson(category)).toList();
}
// omitted functions
}
Why does the notifiyListeners() in the logout function of auth_provider.dart not trigger the consumers to rebuild? Am I missing something else that might cause this issue?
Update after answer
In the providers array of main.dart, I changed the ChangeNotifierProvider to ChangeNotifierProxyProvider. The difference is that the ChangeNotifierProxyProvider allows for a update() callback, so the provider can get updated if AuthProvider updates.
Code example:
ChangeNotifierProxyProvider<AuthProvider, CategoryProvider>(
create: (context) => CategoryProvider(authProvider),
update: (context, authProvider, categoryProvider) => CategoryProvider(authProvider)
),
uj5u.com熱心網友回復:
將Consumer被更新。您的Providers 沒有重新創建它們的值。
Provider.create僅在第一次需要該值時呼叫一次。一個用戶注銷另一個用戶登錄后,同一個CategoryProvider實體仍然存在,所以據Provider了解,沒有理由再創建一個。ApiService存盤在的實體CategoryProvider仍然使用舊令牌,這會導致舊資料加載。
要更新令牌,您需要CategoryProvider使用新令牌更新或重新創建。一種選擇是ChangeNotifierProxyProvider,它提供了一個update回呼引數。
uj5u.com熱心網友回復:
您在單個提供程式中使用了多個提供程式嘗試更改它
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/314882.html
標籤:flutter dart flutter-provider flutter-change-notifier
上一篇:為什么在沒有文本更改的情況下多次呼叫文本更改偵聽器函式
下一篇:帶圓角的文本欄位:錯誤文本行為
