我一直在尝试为一个简单的 SwiftUI 项目创建更小的可重用视图。但是,我得到了意想不到的结果,并且很难理解为什么。
这是我人为的例子来突出这个问题
使用这个例子,你应该如何创建一个可重用的RowView来代替HStack
列表中的
var body: some View {
List(vm.gradings) { item in
// how should you refactor out this ??
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
我正在使用 Firebase 来触发模型更改。即更改成绩以通过或失败并期望列表详细信息视图显示该更改。
上述方法按预期工作,而在列表视图中,当数据更改时,行将更改。
但是,当我尝试重构该视图时,只有一个按预期工作。理想情况下,我想传入Grading
对象,但这不会导致视图刷新。
尝试不同的子视图及其结果
var body: some View {
List(vm.gradings) { item in
// Works
RowA(grade: item.grade, pass: item.pass)
// Fails
// RowB(item: item)
// Fails
// RowC(item: item)
// Default - works as expected
// HStack {
// Text(item.grade)
// Text(item.pass ? "Pass" : "Fail")
// }
}
}
这是 3 行选项
// Works
struct RowA: View {
var grade: String
var pass: Bool
var body: some View {
HStack {
Text(grade)
Text(pass ? "Pass" : "Fail")
}
}
}
// Fails
struct RowB: View {
var item: Grading
var body: some View {
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
// Fails
struct RowC: View {
@State var item: Grading
var body: some View {
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
解决问题
// Allows me to pass in just the model
struct RowD: View {
private var item = Grading()
private var grade: String = ""
private var pass: Bool = false
init(item: Grading) {
self.item = item
self.grade = item.grade
self.pass = item.pass
}
var body: some View {
HStack {
Text(grade)
Text(pass ? "Pass" : "Fail")
}
}
}
我的视图模型
class StudentGradingsUIViewModel: ObservableObject {
@Published var detailedstudent: DetailedStudent
var gradings: [Grading] {
detailedstudent.student.gradings
}
init(student: DetailedStudent) {
self.detailedstudent = student
}
}