Android Jetpack Compose:API响应成功后更新商品购物车计数
解决方案:等待API响应成功后更新购物车计数
核心思路
- 集中管理商品请求状态:ViewModel中用Map跟踪每个商品变体的API请求状态,避免多个商品请求互相覆盖。
- 状态提升与单向数据流:商品列表状态由父组件管理,子组件通过回调更新状态,避免直接修改本地数据。
- 监听API响应更新UI:在商品Item中监听对应商品的请求状态,仅当响应成功且
Result == false时更新计数。
1. 修改ViewModel,跟踪每个商品的请求状态
原ViewModel仅维护单个请求结果,多商品请求会互相覆盖,改用Map存储每个商品变体ID对应的请求状态:
@HiltViewModel class AddProductVM @Inject constructor( private val apiService: ApiService, private val defaultDispatcher: CoroutineDispatcher ): ViewModel() { // 用商品变体ID作为Key,存储每个商品的请求状态 private val _addProductStates = MutableStateFlow<Map<String, ApiResult<AddProduct>>>(emptyMap()) val addProductStates = _addProductStates.asStateFlow() fun addProduct(productId: String, qty: String, productVariantId: String){ // 更新当前商品的状态为加载中 _addProductStates.update { currentMap -> currentMap + (productVariantId to ApiResult.Loading()) } viewModelScope.launch { apiService.addProduct(productId, qty, productVariantId) .flowOn(defaultDispatcher) .catch { // 请求失败,更新状态 _addProductStates.update { currentMap -> currentMap + (productVariantId to ApiResult.Error(it.message ?: "Something went wrong")) } } .collect{ result -> // 请求完成,更新状态 _addProductStates.update { currentMap -> currentMap + (productVariantId to result) } } } } }
2. 修改ProductItem组件,监听响应并更新计数
将商品状态的修改权限交给父组件,同时监听当前商品的API请求状态,处理加载、成功、失败逻辑:
@Composable fun ProductItem( product: Product, onUpdateProductCount: (variantId: String, newCount: Int) -> Unit, addProductViewModel: AddProductVM = hiltViewModel() ) { val addProductStates by addProductViewModel.addProductStates.collectAsState() val currentVariant = product.variants[0] val currentRequestState = addProductStates[currentVariant.id] // 监听请求状态变化,仅当成功且Result==false时更新计数 LaunchedEffect(currentRequestState) { if (currentRequestState is ApiResult.Success) { val isApiError = currentRequestState.data?.error ?: true if (!isApiError) { val newCount = currentVariant.cart_count + 1 onUpdateProductCount(currentVariant.id, newCount) } } } Card(modifier = Modifier.fillMaxWidth()) { Row(modifier = Modifier.fillMaxHeight()) { Column { Row { Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.Center ) { when(currentRequestState) { // 加载中显示进度条 is ApiResult.Loading -> CircularProgressIndicator(modifier = Modifier.size(20.dp)) else -> { if (currentVariant.cart_count > 0) { Text(text = currentVariant.cart_count.toString()) } else { Text( text = "Add To Cart", modifier = Modifier.clickable { val newCount = currentVariant.cart_count + 1 addProductViewModel.addProduct( currentVariant.product_id.toString(), newCount.toString(), currentVariant.id.toString() ) } ) } } } } } } } } }
3. 父组件管理商品列表状态
在商品列表组件中维护可变的商品列表,通过回调更新对应商品的计数:
@Composable fun ProductList(initialProducts: List<Product>) { // 用mutableStateListOf维护可更新的商品列表 val mutableProducts = remember { mutableStateListOf(*initialProducts.toTypedArray()) } LazyColumn { items(mutableProducts) { product -> ProductItem( product = product, onUpdateProductCount = { variantId, newCount -> // 找到对应商品并更新计数 val targetIndex = mutableProducts.indexOfFirst { it.variants[0].id == variantId } if (targetIndex != -1) { val updatedProduct = product.copy( variants = product.variants.map { if (it.id == variantId) it.copy(cart_count = newCount) else it } ) mutableProducts[targetIndex] = updatedProduct } } ) } } }
4. 优化全局响应处理(可选)
如果需要全局处理API响应的日志或提示,修改AddProductResult组件:
@Composable fun AddProductResult(addProductStates: Map<String, ApiResult<AddProduct>>) { addProductStates.values.forEach { state -> when (state) { is ApiResult.Error -> Log.e("addproductapicall", "请求失败: ${state.error}") is ApiResult.Success -> { val isError = state.data?.error ?: true if (isError) { Log.e("addproductapicall", "业务错误: ${state.data?.message}") } else { Log.d("addproductapicall", "请求成功: ${state.data?.message}") } } else -> {} } } }
内容的提问来源于stack exchange,提问作者SasidharanIOS
相关产品推荐
相关产品推荐

