Flutter:ChangeNotifierProxyProvider:未提供更新的正确状态



我正试图将状态从一个ChangeNotifierAuth.dart获取到另一个ChangeNotifierProductsProvider.dart。但是ChangeNotifierProxyProviderAuth提供了不正确的状态数据。

main.dart

void main() => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<Auth>(create: (ctx) => Auth()),
ChangeNotifierProxyProvider<Auth, ProductsProvider>(
create: (context) => ProductsProvider(
Provider.of<Auth>(context, listen: false),
productList: [],
),
update: (ctx, auth, preProducts) {
print("ChangeNotifierProxyProvider Token ${auth.isAuth}");
print("ChangeNotifierProxyProvider Token ${auth.token}");
print("ChangeNotifierProxyProvider Test ${auth.test}");
return ProductsProvider(
auth,
productList:
preProducts == null ? [] : preProducts.getProductList,
);
},
),
ChangeNotifierProvider(create: (ctx) => Cart()),
ChangeNotifierProvider(create: (ctx) => Order()),
ChangeNotifierProvider(create: (ctx) => Auth()),
],
child: MyApp(),
),
);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<Auth>(
builder: (ctx, auth, _) {
print("Builder Token ${auth.isAuth}");
print("Builder Token ${auth.token}");
print("Builder Test ${auth.test}");
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.orange,
fontFamily: "Lato",
),
routes: {
"/": (ctx) => auth.isAuth ? ProductOverviewScreen() : AuthScreen(),
ProductDetailScreen.PRODUCT_DETAIL_ROUTE: (ctx) =>
ProductDetailScreen(),
CartScreen.CART_SCREEN_ROUTE: (ctx) => CartScreen(),
OrderScreen.ORDER_SCREEN_ROUTE: (ctx) => OrderScreen(),
UserProductScreen.USER_PRODUCT_ROUTE: (ctx) => UserProductScreen(),
EditProductScreen.EDIT_PRODUCT_ROUTE: (ctx) => EditProductScreen(),
},
);
},
// ),
);
}
}

Auth.dart

import 'dart:convert';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:shop_app/models/HttpException.dart';
class Auth with ChangeNotifier {
String _token;
String _userId;
DateTime _expiryDate;
String test;
bool get isAuth => token != null;
String get token {
if (_token == null
// && _expiryDate != null &&
// _expiryDate.isAfter(DateTime.now())
) {
return null;
}
return _token;
}
Future<void> _authenticate(String email, String password, String url) async {
final uri = Uri.parse(url);
final response = await http.post(
uri,
body: jsonEncode({
"email": email,
"password": password,
"returnSecureToken": true,
}),
);
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData["error"] != null) {
throw HttpException(responseData["error"]["message"]);
}
_token = responseData["idToken"];
_userId = responseData["localId"];
test = "_token";
// _expiryDate = DateTime.now()
//     .add(Duration(seconds: int.parse(responseData["expiresIn"])));
notifyListeners();
}
Future<void> signUp(String email, String password) async {
const url =
"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[KEY]";
return await _authenticate(email, password, url);
}
Future<void> login(String email, String password) async {
const url =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[KEY]";
return await _authenticate(email, password, url);
}
}

ProductsProvider.dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shop_app/models/HttpException.dart';
import 'package:shop_app/models/Product.dart';
import 'package:shop_app/providers/Auth.dart';
class ProductsProvider with ChangeNotifier {
List<Product> _productList = [];
Auth _auth;
ProductsProvider(this._auth, {List<Product> productList = const []})
: _productList = productList;
Future<void> fetchAndSetProducts() async {
var uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products.json?auth=${_auth.token}");
try {
final response = await http.get(uri);
if (response.body != "null") {
final Map<String, dynamic> decodedJSON = jsonDecode(response.body);
final List<Product> loadedProductList = [];
decodedJSON.forEach((prodId, prodData) {
loadedProductList.add(Product(
id: prodId,
title: prodData["title"],
description: prodData["description"],
price: prodData["price"],
imageUrl: prodData["imageUrl"],
isFavourite: prodData["isFavourite"],
));
});
_productList = loadedProductList;
} else {
_productList = [];
}
notifyListeners();
} catch (error) {
throw error;
}
}
List<Product> get getProductList {
return _productList;
}
Product findById(String id) =>
_productList.firstWhere((element) => element.id == id);
Future<void> addProduct(Product product) async {
var uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products.json");
try {
final responseProduct =
await http.post(uri, body: jsonEncode(product.toJSon()));
final finalProduct = Product(
id: jsonDecode(responseProduct.body)["name"],
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl);
_productList.add(finalProduct);
notifyListeners();
return Future.value();
} catch (error) {
throw error;
}
}
Future<void> updateProduct(String id, Product product) async {
var productIndex = _productList.indexWhere((element) => element.id == id);
if (productIndex >= 0) {
var uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products/$id.json");
try {
await http.patch(uri,
body: jsonEncode({
"title": product.title,
"description": product.description,
"price": product.price,
"imageUrl": product.imageUrl,
"isFavourite": product.isFavourite,
}));
_productList[productIndex] = product;
notifyListeners();
} catch (error) {
throw error;
}
}
}
Future<void> deleteProduct(String id) async {
final uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products/$id.json");
final existingProductIndex =
_productList.indexWhere((element) => element.id == id);
var existingProduct = _productList[existingProductIndex];
_productList.removeAt(existingProductIndex);
final response = await http.delete(uri);
if (response.statusCode >= 400) {
_productList.insert(existingProductIndex, existingProduct);
notifyListeners();
throw HttpException("Could not delete product");
}
existingProduct = null;
notifyListeners();
}
}

单击登录按钮后,Auth.dart的登录方法将被触发。从firebase获取令牌后,屏幕更新为ProductOverviewScreen。但是CCD_ 12不能获取项目,因为CCD_。

输出:

Builder Token true
Builder Token eyJhbGciOiJSUzI1NiIsImtpZCI6IjNkOWNmYWE4OGVmMDViNDI0YmU2MjA1ZjQ2YjE4OGQ3MzI1N2JjNDIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vZmx1dHRlci1zaG9wLWFwcC0zMDM1YSIsImF1ZCI6ImZsdXR0ZXItc2hvcC1hcHAtMzAzNWEiLCJhdXRoX3RpbWUiOjE2MjE3NzUxMDYsInVzZXJfaWQiOiJ5Y0dVVWhwYTFvY2EwMThlYUx4VGZkQnRNbmsyIiwic3ViIjoieWNHVVVocGExb2NhMDE4ZWFMeFRmZEJ0TW5rMiIsImlhdCI6MTYyMTc3NTEwNiwiZXhwIjoxNjIxNzc4NzA2LCJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsidGVzdEB0ZXN0LmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.t1xosbzllt79NV6FQ79mTQ2J3VCR5fILKMxE5-ObOxMI2DtD_kMg2AP9NXm_f1IsLF9AT5xeXeVU36goVDLQuKSWmbejOANDn7hsF6VzZMyBV1P9qehXpWgSmCscjXT8FRlKViZzxOZwCWSHS1M94n92YYhwaZltiDcQ87hhv7ZdKyLrlDsUPfr7IjNBeSVDmzws_9uBoZwYKRYCW1veWPc7HPWtdP8QT7K_vkCEvGLHfxbmVHOgUkDMzLqhgusZl34GCPVKr_PSpQ9SgC7Mg95QeZyzYzPmhasGUptq5pQsjEoqTxgYHnmEuMRRjksZT5lbfsQQFOJMsXBTIC7RDQ
Builder Test _token
ChangeNotifierProxyProvider Token false
ChangeNotifierProxyProvider Token null
ChangeNotifierProxyProvider Test null
Error: Expected a value of type 'int', but got one of type 'String'
at Object.throw_ [as throw] (http://localhost:1344/dart_sdk.js:5333:11)
at ProductProvider.ProductsProvider.new.fetchAndSetProducts (http://localhost:1344/packages/shop_app/providers/ProductProvider.dart.lib.js:84:21)
at fetchAndSetProducts.next (<anonymous>)
at http://localhost:1344/dart_sdk.js:39031:33
at _RootZone.runUnary (http://localhost:1344/dart_sdk.js:38888:58)
at _FutureListener.thenAwait.handleValue (http://localhost:1344/dart_sdk.js:33874:29)
at handleValueCallback (http://localhost:1344/dart_sdk.js:34434:49)
at Function._propagateToListeners (http://localhost:1344/dart_sdk.js:34472:17)
at _Future.new.[_completeWithValue] (http://localhost:1344/dart_sdk.js:34314:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:1344/dart_sdk.js:34337:35)
at Object._microtaskLoop (http://localhost:1344/dart_sdk.js:39175:13)
at _startMicrotaskLoop (http://localhost:1344/dart_sdk.js:39181:13)
at http://localhost:1344/dart_sdk.js:34688:9

我正在学习飞镖和飞镖。我不确定我错过了什么。有人能帮我解决这个问题吗。

我能够找到导致此问题的原因。我似乎正在重新初始化AuthChangeNotificationProvider。如果您看到MultiProvider构造函数提供程序参数中的最后一行。

如果其他人遇到此类问题,请确保您已按正确顺序指定了提供商。

产品Id定义为int/Integer,但firebase中的解析器是String。您需要将产品Id更改为字符串或使用int.parse(prodId(

最新更新