如何正确更新 firestore 数据库值
how to update firestore database value correctly
我正在努力在我的 Flutter 应用程序中构建基本的购物功能。我是编码和 Flutter 的新手。当用户单击 PlaceOrderPageContainer(按钮)以确认签出时,调用 addOrderDetails() 方法,然后更新 Firebase 数据库。除了添加为零的总金额之外,Firestore 数据库中的所有内容都在正确更新,无论购物车中的总金额如何。我在控制台中没有收到任何错误,但很明显我的代码编写不正确。任何帮助将不胜感激。如果有帮助,我可以添加任何其他代码。
class ShoppingCartPage extends StatefulWidget {
const ShoppingCartPage({Key? key}) : super(key: key);
@override
_ShoppingCartPageState createState() => _ShoppingCartPageState();
}
class _ShoppingCartPageState extends State<ShoppingCartPage> {
late double totalAmount;
@override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmountProvider>(
context,
listen: false,
).display(0);
}
@override
Widget build(BuildContext context) {
return Consumer2<TotalAmountProvider, CartItemCounterProvider>(
builder: (context, amountProvider, cartProvider, c) {
return SafeArea(
child: Scaffold(
appBar: const ShoppingCartAppBar(),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
if (ShoppingApp.sharedPreferences
.getStringList(
ShoppingApp.userCartList,
)
?.length ==
1) {
Fluttertoast.showToast(msg: ToastString.cartEmpty);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddressPage(
totalAmount: totalAmount,
),
),
);
}
},
icon: const Icon(
Icons.navigate_next,
),
label: Text(
ButtonString.checkOut.toUpperCase(),
),
),
body: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child:
Consumer2<TotalAmountProvider, CartItemCounterProvider>(
builder: (context, amountProvider, cartProvider, c) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: cartProvider.count == 0
? Container()
: Text(
'Total Price: $${amountProvider.totalAmount.toString()}',
style: Theme.of(context).textTheme.headline6,
),
),
);
},
),
),
StreamBuilder<QuerySnapshot>(
stream: ShoppingApp.firestore
.collection('items')
.where('shortInfo',
whereIn: ShoppingApp.sharedPreferences
.getStringList(ShoppingApp.userCartList))
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
return !snapshot.hasData
? const AdaptiveCircularProgressSliver()
: snapshot.data.docs.isEmpty
? const EmptyShoppingCartContainer()
: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
ItemModel model = ItemModel.fromJson(
snapshot.data.docs[index].data(),
);
if (index == 0) {
totalAmount = 0;
// totalAmount = model.price! + totalAmount;
} else {
totalAmount =
model.price! + totalAmount;
}
if (snapshot.data?.docs.length - 1 ==
index) {
WidgetsBinding.instance!
.addPostFrameCallback((timeStamp) {
Provider.of<TotalAmountProvider>(
context,
listen: false)
.display(totalAmount);
});
}
return sourceInfo(
model,
context,
removeCartFunction: () =>
removeItemFromUserCart(
model.shortInfo as String,
),
);
},
childCount: snapshot.hasData
? snapshot.data?.docs.length
: 0,
),
);
}),
],
),
),
);
},
);
}
Future<void> removeItemFromUserCart(
String shortInfoAsID,
) async {
List<String>? tempCartList = ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
);
tempCartList?.remove(shortInfoAsID);
await ShoppingApp.firestore
.collection(ShoppingApp.collectionUser)
.doc(ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
))
.update({
ShoppingApp.userCartList: tempCartList,
}).then((value) {
Fluttertoast.showToast(
msg: ToastString.removeFromCart,
);
ShoppingApp.sharedPreferences.setStringList(
ShoppingApp.userCartList,
tempCartList as List<String>,
);
Provider.of<CartItemCounterProvider>(
context,
listen: false,
).displayResult();
totalAmount = 0;
});
}
}
class AddressPage extends StatefulWidget {
const AddressPage({
Key? key,
required this.totalAmount,
}) : super(key: key);
final double totalAmount;
@override
_AddressPageState createState() => _AddressPageState();
}
class _AddressPageState extends State<AddressPage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: AdaptiveLayoutScaffold(
appBar: const AddressPageAppBar(),
floatingActionButton: const AddNewAddressFAB(),
landscapeBodyWidget: Container(),
portraitBodyWidget: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
const AddressPageHeadline(
headlineText: ShoppingPageString.selectAddress,
),
Consumer<AddressChangerProvider>(builder: (
context,
address,
c,
) {
return Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: ShoppingApp.firestore
.collection(ShoppingApp.collectionUser)
.doc(ShoppingApp.sharedPreferences
.getString(ShoppingApp.userUID))
.collection(ShoppingApp.subCollectionAddress)
.snapshots(),
builder: (context, snapshot) {
return !snapshot.hasData
? const AdaptiveCircularProgressCenter()
: snapshot.data!.docs.isEmpty
? const EmptyShippingAddressContainer()
: ListView.builder(
itemCount: snapshot.data?.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return AddressCard(
addressID: snapshot.data?.docs[index].id
as String,
currentIndex: address.count,
model: AddressModel.fromJson(
snapshot.data?.docs[index].data()
as Map<String, dynamic>,
),
totalAmount: widget.totalAmount,
value: index,
);
},
);
}),
);
}),
],
),
),
);
}
}
class AddressCard extends StatefulWidget {
const AddressCard({
Key? key,
required this.addressID,
required this.currentIndex,
required this.model,
required this.totalAmount,
required this.value,
}) : super(key: key);
final String addressID;
final int currentIndex;
final AddressModel model;
final double totalAmount;
final int value;
@override
_AddressCardState createState() => _AddressCardState();
}
class _AddressCardState extends State<AddressCard> {
@override
Widget build(BuildContext context) {
return AddressCardContainer(
onTap: () {
Provider.of<AddressChangerProvider>(
context,
listen: false,
).displayResult(widget.value);
},
addressCardColumn: AddressCardColumn(
children: [
Row(
children: [
AddressCardRadioButton(
groupValue: widget.currentIndex,
onChanged: (value) {
Provider.of<AddressChangerProvider>(
context,
listen: false,
).displayResult(
value as int,
);
},
value: widget.value,
),
AddressCardContent(
city: widget.model.city as String,
fullName: widget.model.name as String,
phoneNumber: widget.model.phoneNumber as String,
postalCode: widget.model.postalCode as String,
state: widget.model.state as String,
streetAddress: widget.model.streetAddress as String,
),
],
),
widget.value == Provider.of<AddressChangerProvider>(context).count
? ShippingAddressProceedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (
context,
) =>
PlaceOrderPaymentPage(
addressID: widget.addressID,
totalAmount: widget.totalAmount,
),
),
);
},
)
: Container(),
],
),
);
}
}
class PlaceOrderPaymentPage extends StatefulWidget {
const PlaceOrderPaymentPage({
Key? key,
required this.addressID,
required this.totalAmount,
}) : super(key: key);
final String addressID;
final double totalAmount;
@override
_PlaceOrderPaymentPageState createState() => _PlaceOrderPaymentPageState();
}
class _PlaceOrderPaymentPageState extends State<PlaceOrderPaymentPage> {
@override
Widget build(BuildContext context) {
return AdaptiveLayoutScaffold(
appBar: const PlaceOrderPaymentPageAppBar(),
landscapeBodyWidget: Container(),
portraitBodyWidget: PlaceOrderPageContainer(
orderOnPressed: () => addOrderDetails(),
),
);
}
void addOrderDetails() {
final time = DateTime.now().millisecondsSinceEpoch;
writeOrderDetailsForUser({
ShoppingApp.addressID: widget.addressID,
ShoppingApp.totalAmount: widget.totalAmount,
'orderBy': ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
),
ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
),
ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
ShoppingApp.orderTime: time.toString(),
ShoppingApp.isSuccess: true,
});
writeOrderDetailsForAdmin({
ShoppingApp.addressID: widget.addressID,
ShoppingApp.totalAmount: widget.totalAmount,
'orderBy': ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
),
ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
),
ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
ShoppingApp.orderTime: time.toString(),
ShoppingApp.isSuccess: true,
}).whenComplete(() => {
emptyCartNow(),
});
}
void emptyCartNow() {
ShoppingApp.sharedPreferences.setStringList(ShoppingApp.userCartList, [
'garbageValue',
]);
List<String>? tempList = ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
);
FirebaseFirestore.instance
.collection('users')
.doc(ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
))
.update({
ShoppingApp.userCartList: tempList,
}).then((value) {
ShoppingApp.sharedPreferences.setStringList(
ShoppingApp.userCartList,
tempList as List<String>,
);
Provider.of<CartItemCounterProvider>(
context,
listen: false,
).displayResult();
});
Fluttertoast.showToast(
msg: ToastString.orderPlacedSuccessfully,
);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ShoppingPage(),
),
);
}
Future<void> writeOrderDetailsForUser(
Map<String, dynamic> data,
) async {
await ShoppingApp.firestore
.collection(ShoppingApp.collectionUser)
.doc(ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID))
.collection(ShoppingApp.collectionOrders)
.doc(
ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
data['orderTime'],
)
.set(data);
}
Future<void> writeOrderDetailsForAdmin(Map<String, dynamic> data) async {
await ShoppingApp.firestore
.collection(ShoppingApp.collectionOrders)
.doc(
ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
data['orderTime'],
)
.set(data);
}
}
class CartItemCounterProvider extends ChangeNotifier {
final int _counter = (ShoppingApp.sharedPreferences
.getStringList(
ShoppingApp.userCartList,
)
?.length ??
0) -
1;
int get count => _counter;
Future<void> displayResult() async {
int _counter = (ShoppingApp.sharedPreferences
.getStringList(
ShoppingApp.userCartList,
)
?.length ??
0) -
1;
await Future.delayed(
const Duration(
milliseconds: 100,
), () {
notifyListeners();
});
}
}
CartCheckOutFAB 首先总是用值 0 实例化,因为 ShoppingCartPage 状态没有改变。
您可以尝试将 Consumer2 作为 AdaptiveLayoutScaffold 的父级移动并实例化 CartCheckOutFAB amountProvider.totalAmount
- 如果它不起作用,您可以提供 CartCheckOutFAB 小部件 class。
我正在努力在我的 Flutter 应用程序中构建基本的购物功能。我是编码和 Flutter 的新手。当用户单击 PlaceOrderPageContainer(按钮)以确认签出时,调用 addOrderDetails() 方法,然后更新 Firebase 数据库。除了添加为零的总金额之外,Firestore 数据库中的所有内容都在正确更新,无论购物车中的总金额如何。我在控制台中没有收到任何错误,但很明显我的代码编写不正确。任何帮助将不胜感激。如果有帮助,我可以添加任何其他代码。
class ShoppingCartPage extends StatefulWidget {
const ShoppingCartPage({Key? key}) : super(key: key);
@override
_ShoppingCartPageState createState() => _ShoppingCartPageState();
}
class _ShoppingCartPageState extends State<ShoppingCartPage> {
late double totalAmount;
@override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmountProvider>(
context,
listen: false,
).display(0);
}
@override
Widget build(BuildContext context) {
return Consumer2<TotalAmountProvider, CartItemCounterProvider>(
builder: (context, amountProvider, cartProvider, c) {
return SafeArea(
child: Scaffold(
appBar: const ShoppingCartAppBar(),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
if (ShoppingApp.sharedPreferences
.getStringList(
ShoppingApp.userCartList,
)
?.length ==
1) {
Fluttertoast.showToast(msg: ToastString.cartEmpty);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddressPage(
totalAmount: totalAmount,
),
),
);
}
},
icon: const Icon(
Icons.navigate_next,
),
label: Text(
ButtonString.checkOut.toUpperCase(),
),
),
body: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child:
Consumer2<TotalAmountProvider, CartItemCounterProvider>(
builder: (context, amountProvider, cartProvider, c) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: cartProvider.count == 0
? Container()
: Text(
'Total Price: $${amountProvider.totalAmount.toString()}',
style: Theme.of(context).textTheme.headline6,
),
),
);
},
),
),
StreamBuilder<QuerySnapshot>(
stream: ShoppingApp.firestore
.collection('items')
.where('shortInfo',
whereIn: ShoppingApp.sharedPreferences
.getStringList(ShoppingApp.userCartList))
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
return !snapshot.hasData
? const AdaptiveCircularProgressSliver()
: snapshot.data.docs.isEmpty
? const EmptyShoppingCartContainer()
: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
ItemModel model = ItemModel.fromJson(
snapshot.data.docs[index].data(),
);
if (index == 0) {
totalAmount = 0;
// totalAmount = model.price! + totalAmount;
} else {
totalAmount =
model.price! + totalAmount;
}
if (snapshot.data?.docs.length - 1 ==
index) {
WidgetsBinding.instance!
.addPostFrameCallback((timeStamp) {
Provider.of<TotalAmountProvider>(
context,
listen: false)
.display(totalAmount);
});
}
return sourceInfo(
model,
context,
removeCartFunction: () =>
removeItemFromUserCart(
model.shortInfo as String,
),
);
},
childCount: snapshot.hasData
? snapshot.data?.docs.length
: 0,
),
);
}),
],
),
),
);
},
);
}
Future<void> removeItemFromUserCart(
String shortInfoAsID,
) async {
List<String>? tempCartList = ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
);
tempCartList?.remove(shortInfoAsID);
await ShoppingApp.firestore
.collection(ShoppingApp.collectionUser)
.doc(ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
))
.update({
ShoppingApp.userCartList: tempCartList,
}).then((value) {
Fluttertoast.showToast(
msg: ToastString.removeFromCart,
);
ShoppingApp.sharedPreferences.setStringList(
ShoppingApp.userCartList,
tempCartList as List<String>,
);
Provider.of<CartItemCounterProvider>(
context,
listen: false,
).displayResult();
totalAmount = 0;
});
}
}
class AddressPage extends StatefulWidget {
const AddressPage({
Key? key,
required this.totalAmount,
}) : super(key: key);
final double totalAmount;
@override
_AddressPageState createState() => _AddressPageState();
}
class _AddressPageState extends State<AddressPage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: AdaptiveLayoutScaffold(
appBar: const AddressPageAppBar(),
floatingActionButton: const AddNewAddressFAB(),
landscapeBodyWidget: Container(),
portraitBodyWidget: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
const AddressPageHeadline(
headlineText: ShoppingPageString.selectAddress,
),
Consumer<AddressChangerProvider>(builder: (
context,
address,
c,
) {
return Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: ShoppingApp.firestore
.collection(ShoppingApp.collectionUser)
.doc(ShoppingApp.sharedPreferences
.getString(ShoppingApp.userUID))
.collection(ShoppingApp.subCollectionAddress)
.snapshots(),
builder: (context, snapshot) {
return !snapshot.hasData
? const AdaptiveCircularProgressCenter()
: snapshot.data!.docs.isEmpty
? const EmptyShippingAddressContainer()
: ListView.builder(
itemCount: snapshot.data?.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return AddressCard(
addressID: snapshot.data?.docs[index].id
as String,
currentIndex: address.count,
model: AddressModel.fromJson(
snapshot.data?.docs[index].data()
as Map<String, dynamic>,
),
totalAmount: widget.totalAmount,
value: index,
);
},
);
}),
);
}),
],
),
),
);
}
}
class AddressCard extends StatefulWidget {
const AddressCard({
Key? key,
required this.addressID,
required this.currentIndex,
required this.model,
required this.totalAmount,
required this.value,
}) : super(key: key);
final String addressID;
final int currentIndex;
final AddressModel model;
final double totalAmount;
final int value;
@override
_AddressCardState createState() => _AddressCardState();
}
class _AddressCardState extends State<AddressCard> {
@override
Widget build(BuildContext context) {
return AddressCardContainer(
onTap: () {
Provider.of<AddressChangerProvider>(
context,
listen: false,
).displayResult(widget.value);
},
addressCardColumn: AddressCardColumn(
children: [
Row(
children: [
AddressCardRadioButton(
groupValue: widget.currentIndex,
onChanged: (value) {
Provider.of<AddressChangerProvider>(
context,
listen: false,
).displayResult(
value as int,
);
},
value: widget.value,
),
AddressCardContent(
city: widget.model.city as String,
fullName: widget.model.name as String,
phoneNumber: widget.model.phoneNumber as String,
postalCode: widget.model.postalCode as String,
state: widget.model.state as String,
streetAddress: widget.model.streetAddress as String,
),
],
),
widget.value == Provider.of<AddressChangerProvider>(context).count
? ShippingAddressProceedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (
context,
) =>
PlaceOrderPaymentPage(
addressID: widget.addressID,
totalAmount: widget.totalAmount,
),
),
);
},
)
: Container(),
],
),
);
}
}
class PlaceOrderPaymentPage extends StatefulWidget {
const PlaceOrderPaymentPage({
Key? key,
required this.addressID,
required this.totalAmount,
}) : super(key: key);
final String addressID;
final double totalAmount;
@override
_PlaceOrderPaymentPageState createState() => _PlaceOrderPaymentPageState();
}
class _PlaceOrderPaymentPageState extends State<PlaceOrderPaymentPage> {
@override
Widget build(BuildContext context) {
return AdaptiveLayoutScaffold(
appBar: const PlaceOrderPaymentPageAppBar(),
landscapeBodyWidget: Container(),
portraitBodyWidget: PlaceOrderPageContainer(
orderOnPressed: () => addOrderDetails(),
),
);
}
void addOrderDetails() {
final time = DateTime.now().millisecondsSinceEpoch;
writeOrderDetailsForUser({
ShoppingApp.addressID: widget.addressID,
ShoppingApp.totalAmount: widget.totalAmount,
'orderBy': ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
),
ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
),
ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
ShoppingApp.orderTime: time.toString(),
ShoppingApp.isSuccess: true,
});
writeOrderDetailsForAdmin({
ShoppingApp.addressID: widget.addressID,
ShoppingApp.totalAmount: widget.totalAmount,
'orderBy': ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
),
ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
),
ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
ShoppingApp.orderTime: time.toString(),
ShoppingApp.isSuccess: true,
}).whenComplete(() => {
emptyCartNow(),
});
}
void emptyCartNow() {
ShoppingApp.sharedPreferences.setStringList(ShoppingApp.userCartList, [
'garbageValue',
]);
List<String>? tempList = ShoppingApp.sharedPreferences.getStringList(
ShoppingApp.userCartList,
);
FirebaseFirestore.instance
.collection('users')
.doc(ShoppingApp.sharedPreferences.getString(
ShoppingApp.userUID,
))
.update({
ShoppingApp.userCartList: tempList,
}).then((value) {
ShoppingApp.sharedPreferences.setStringList(
ShoppingApp.userCartList,
tempList as List<String>,
);
Provider.of<CartItemCounterProvider>(
context,
listen: false,
).displayResult();
});
Fluttertoast.showToast(
msg: ToastString.orderPlacedSuccessfully,
);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ShoppingPage(),
),
);
}
Future<void> writeOrderDetailsForUser(
Map<String, dynamic> data,
) async {
await ShoppingApp.firestore
.collection(ShoppingApp.collectionUser)
.doc(ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID))
.collection(ShoppingApp.collectionOrders)
.doc(
ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
data['orderTime'],
)
.set(data);
}
Future<void> writeOrderDetailsForAdmin(Map<String, dynamic> data) async {
await ShoppingApp.firestore
.collection(ShoppingApp.collectionOrders)
.doc(
ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
data['orderTime'],
)
.set(data);
}
}
class CartItemCounterProvider extends ChangeNotifier {
final int _counter = (ShoppingApp.sharedPreferences
.getStringList(
ShoppingApp.userCartList,
)
?.length ??
0) -
1;
int get count => _counter;
Future<void> displayResult() async {
int _counter = (ShoppingApp.sharedPreferences
.getStringList(
ShoppingApp.userCartList,
)
?.length ??
0) -
1;
await Future.delayed(
const Duration(
milliseconds: 100,
), () {
notifyListeners();
});
}
}
CartCheckOutFAB 首先总是用值 0 实例化,因为 ShoppingCartPage 状态没有改变。
您可以尝试将 Consumer2
- 如果它不起作用,您可以提供 CartCheckOutFAB 小部件 class。