SwiftUI使用@State管理日历选中日期时随机字符串重复生成问题咨询
问题判断
你的判断完全正确。
@State 属性发生变更时,会触发其所属的整个 View 结构体的 body 重新渲染。你的
Summary是Reservations视图的内部方法,和selectedDate同属一个视图层级,因此selectedDate更新后整个Summary都会重绘,调用随机字符串生成函数,导致 ID 每次都变化。
解决方案
有两种常用的低成本改造方案可以解决这个问题:
方案1:将随机字符串存入独立的@State属性,仅生成一次
因为随机ID只需要在页面初始化时生成一次,你可以单独声明一个@State存储该值,避免每次重绘重复调用生成函数:
struct Reservations: View { @Environment(\.calendar) private var calendar @State private var selectedDate: Date = Self.now // 新增存储随机ID的State @State private var randomID: String = "" private static var now = Date() var body: some View { Summary() ReservationsCalendar() // 页面首次出现时生成一次随机ID .onAppear { randomID = generateRandomString(length: 7).uppercased() } } }
然后把 Summary 里的 generateRandomString 调用替换为 randomID 即可。
方案2:拆分视图,隔离不需要刷新的组件
你可以把随机ID的展示部分封装为独立的子View,只要这个子View的输入参数不包含 selectedDate,SwiftUI 就会判断它的依赖没有变化,不会在 selectedDate 更新时重绘该子View:
// 新增独立的随机ID视图 struct RandomIDView: View { private let randomID: String init(length: Int) { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" randomID = String((0..<length).map{ _ in letters.randomElement()! }).uppercased() } var body: some View { Text(randomID) .foregroundColor(.yellow) .padding(.horizontal, 10) .frame(height: 25) .background( Capsule() .fill(.black.opacity(0.2)) ) } }
替换原 Summary 里的对应代码即可:
Text("ID").foregroundColor(.white) RandomIDView(length: 7)
跨视图修改值的替代方案
如果需要修改不在同一视图的单个值,根据视图层级复杂度选择即可:
- 父子视图直接传值:用
@Binding即可,你当前ReservationsCal用@Binding接收selectedDate的方案本身是正确的,没有问题 - 多层级/多无关视图共享值:iOS 17+ 用
@Observable配合环境变量注入,iOS 16及以下用@StateObject+@EnvironmentObject实现全局共享状态即可。
内容的提问来源于stack exchange,提问作者kAiN
相关产品推荐
相关产品推荐

