
- 在MomentListItem中新增点赞功能,用户点击按钮可触发点赞请求。 - 使用MVVM+Combine架构管理点赞状态,确保UI与状态同步。 - 添加加载状态和错误处理,提升用户体验和交互反馈。 - 更新相关视图以支持新的点赞逻辑,优化代码可读性和维护性。
7.7 KiB
7.7 KiB
MomentListItem 点赞功能实现 (MVVM+Combine)
需求分析
- 用户可以点击 like 按钮
- 点击 like 按钮时,触发 LikeDynamicRequest 请求
- 当 moment.isLike 为 true 时,请求的 status 参数传 0(取消点赞)
- 当 moment.isLike 为 false 时,请求的 status 参数传 1(点赞)
- 请求成功后,更新 MomentListItem 的 like 状态
架构选择
使用 MVVM+Combine 架构,参考 MomentListHomeViewModel 的实现模式:
- 不使用 TCA 框架
- 使用 @State 管理本地状态
- 使用 LiveAPIService 直接发起 API 请求
- 使用 Task 和 async/await 处理异步操作
实施计划
文件结构
- ✅ 修改:
yana/MVVM/View/MomentListItem.swift
核心组件设计
-
状态管理:
@State private var isLikeLoading = false
- 点赞加载状态@State private var localIsLike: Bool
- 本地点赞状态@State private var localLikeCount: Int
- 本地点赞数量
-
API 请求:
- 使用
LiveAPIService()
直接创建服务实例 - 使用
UserInfoManager.getCurrentUserId()
获取当前用户ID - 使用
LikeDynamicRequest
创建请求
- 使用
-
点赞处理逻辑:
handleLikeTap()
- 处理点赞按钮点击performLikeRequest()
- 执行点赞 API 请求
实施步骤
- ✅ 移除 TCA 相关导入和依赖
- ✅ 添加 @State 状态变量
- ✅ 实现点赞按钮的点击处理
- ✅ 实现 API 请求逻辑(参考 MomentListHomeViewModel)
- ✅ 更新 UI 显示状态
- ✅ 添加错误处理和加载状态
技术要点
- 使用
LiveAPIService()
直接创建服务实例 - 使用
UserInfoManager.getCurrentUserId()
获取当前用户ID - 使用
APILoadingManager
显示错误信息 - 使用
debugInfoSync
和debugErrorSync
记录日志 - 使用
MainActor.run
确保 UI 更新在主线程
实现细节
状态初始化
init(moment: MomentsInfo, onImageTap: @escaping (([String], Int)) -> Void = { (arg) in let (_, _) = arg; }) {
self.moment = moment
self.onImageTap = onImageTap
// 初始化本地状态
self._localIsLike = State(initialValue: moment.isLike)
self._localLikeCount = State(initialValue: moment.likeCount)
}
点赞按钮 UI
Button(action: {
if !isLikeLoading {
handleLikeTap()
}
}) {
HStack(spacing: 4) {
if isLikeLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: localIsLike ? .red : .white.opacity(0.8)))
.scaleEffect(0.8)
} else {
Image(systemName: localIsLike ? "heart.fill" : "heart")
.font(.system(size: 16))
}
Text("\(localLikeCount)")
.font(.system(size: 14))
}
.foregroundColor(localIsLike ? .red : .white.opacity(0.8))
}
.disabled(isLikeLoading)
API 请求逻辑
private func performLikeRequest() async {
// 设置加载状态
await MainActor.run {
isLikeLoading = true
}
do {
// 获取当前用户ID
guard let currentUserId = await UserInfoManager.getCurrentUserId(),
let currentUserIdInt = Int(currentUserId) else {
await MainActor.run {
isLikeLoading = false
}
setAPILoadingErrorSync(UUID(), errorMessage: "无法获取用户信息,请重新登录")
return
}
// 确定请求参数
let status = localIsLike ? 0 : 1 // 0: 取消点赞, 1: 点赞
// 创建 API 服务实例
let apiService = LiveAPIService()
// 创建请求
let request = LikeDynamicRequest(
dynamicId: moment.dynamicId,
uid: moment.uid,
status: status,
likedUid: currentUserIdInt,
worldId: moment.worldId
)
debugInfoSync("📡 MomentListItem: 发送点赞请求")
debugInfoSync(" 动态ID: \(moment.dynamicId)")
debugInfoSync(" 当前状态: \(localIsLike)")
debugInfoSync(" 请求状态: \(status)")
// 发起请求
let response: LikeDynamicResponse = try await apiService.request(request)
await MainActor.run {
isLikeLoading = false
// 处理响应
if let data = response.data, let success = data.success, success {
// 更新本地状态
localIsLike = !localIsLike
localLikeCount = data.likeCount ?? localLikeCount
debugInfoSync("✅ MomentListItem: 点赞操作成功")
debugInfoSync(" 动态ID: \(moment.dynamicId)")
debugInfoSync(" 新状态: \(localIsLike)")
debugInfoSync(" 新数量: \(localLikeCount)")
} else {
// 显示错误信息
let errorMessage = response.message.isEmpty ? "点赞失败,请重试" : response.message
setAPILoadingErrorSync(UUID(), errorMessage: errorMessage)
debugErrorSync("❌ MomentListItem: 点赞操作失败")
debugErrorSync(" 动态ID: \(moment.dynamicId)")
debugErrorSync(" 错误: \(errorMessage)")
}
}
} catch {
await MainActor.run {
isLikeLoading = false
}
setAPILoadingErrorSync(UUID(), errorMessage: error.localizedDescription)
debugErrorSync("❌ MomentListItem: 点赞请求异常")
debugErrorSync(" 动态ID: \(moment.dynamicId)")
debugErrorSync(" 错误: \(error.localizedDescription)")
}
}
架构对比
与 TCA 架构的区别
方面 | TCA 架构 | MVVM+Combine 架构 |
---|---|---|
依赖注入 | @Dependency(.apiService) | LiveAPIService() |
状态管理 | @ObservableState | @State |
异步处理 | Effect.task | Task + async/await |
错误处理 | 通过 Effect 处理 | 直接 try-catch |
复杂度 | 较高 | 较低 |
与 MomentListHomeViewModel 的一致性
- ✅ 使用相同的 API 服务创建方式
- ✅ 使用相同的错误处理模式
- ✅ 使用相同的日志记录方式
- ✅ 使用相同的用户验证逻辑
功能特性
交互体验
- 即时反馈:点击后立即显示加载状态
- 状态切换:成功后在点赞/取消点赞状态间切换
- 数量更新:实时更新点赞数量显示
- 错误处理:网络错误或服务器错误时显示友好提示
状态管理
- 本地状态:使用
@State
管理本地点赞状态,避免影响其他组件 - 加载状态:防止重复点击,提供视觉反馈
- 错误恢复:请求失败时保持原有状态
安全性
- 用户验证:确保用户已登录才能点赞
- 参数验证:正确传递点赞状态参数
- 错误边界:完善的错误处理机制
测试要点
- 点赞状态切换正确(true → false, false → true)
- 点赞数量实时更新
- 加载状态显示正常
- 网络错误处理正确
- 用户未登录时的错误提示
- 重复点击防护
- 与其他组件的状态同步
完成状态
- 移除 TCA 相关代码
- 实现 MVVM+Combine 架构
- 实现状态管理
- 实现点赞按钮 UI
- 实现 API 请求逻辑
- 实现错误处理
- 实现加载状态
- 添加日志记录
- 代码审查和优化
注意事项
- 本实现使用本地状态管理,不会影响其他使用相同动态数据的组件
- 如果需要全局状态同步,建议在父组件中实现状态管理
- 点赞操作是幂等的,重复请求不会产生副作用
- 错误处理使用全局的 APILoadingManager,确保用户体验一致
- 架构选择符合项目要求,不使用 TCA 框架