通过更改 SwiftUI 中的 @State 变量刷新视图不起作用
Refreshing view by changing @State variable in SwiftUI not working
所以为了简单起见,我将首先描述我的代码的运行方式。我有一个通过使用 ForEach 循环遍历 AWS 数据库生成的列表。
List{
ForEach(self.data.database1){ row in
HStack {
Button("\((row.name)!)") {
self.selectedItem = row.id
self.selectedItemName = row.poi!
self.pressedItem = true
}
Spacer()
Button("Delete") {
self.selectedItem = row.id
self.showDeleteItemView = true
//this brings up a view that can confirm you want to delete
}.buttonStyle(BorderlessButtonStyle())
}
}
}
列表中的每一行都包含一个“删除”按钮。此删除按钮打开如下所示的视图:
if self.showDeleteEventView == true {
ConfirmActionView(showView: self.$showDeleteItemView, actionName: "delete this event", function: {
for item in self.data.database1{
if self.selectedItem == item.id{
DispatchQueue.main.async {
self.data.deleteItem(id: event.id)
self.reloadView.toggle()
}
}
}
}, buttonLabel: "Delete")
}
观点是:
struct ConfirmActionView: View {
@Binding var showView: Bool
var actionName: String
var function: () -> Void
var buttonLabel: String
var body: some View {
ZStack {
VStack {
HStack {
Spacer()
Button("X") {
self.showView = false
}
}
Text("Are you sure you want to \(self.actionName)?")
Spacer()
HStack {
Button("\(self.buttonLabel)") {
print("confirmed action")
self.function()
self.showView = false
}
Button("Cancel") {
self.showView = false
}
.padding(EdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6))
}
}.frame(width: 300, height: 150)
}
}
}
deleteItem() 函数如下:
func deleteItem(id: Int) {
let baseUrl = URL(string: itemUrl)
let deletionUrl = baseUrl!.appendingPathComponent("\(id)")
print("Deletion URL with appended id: \(deletionUrl.absoluteString)")
var request = URLRequest(url: deletionUrl)
request.httpMethod = "DELETE"
print(token) // ensure this is correct
request.allHTTPHeaderFields = ["Authorization": "Token \(token)"]
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Encountered network error: \(error)")
return
}
if let httpResponse = response as? HTTPURLResponse {
// this is basically also debugging code
print("Endpoint responded with status: \(httpResponse.statusCode)")
print(" with headers:\n\(httpResponse.allHeaderFields)")
}
// Debug output of the data:
if let data = data {
let payloadAsSimpleString = String(data: data, encoding: .utf8) ?? "(can't parse payload)"
print("Response contains payload\n\(payloadAsSimpleString)")
}
}
task.resume()
}
stateVariable1 是用于保存行中项目名称的变量。 reloadView 是一个@State 布尔变量,所以我想如果我切换它,视图应该在从数据库中删除项目后刷新。代码的功能与我想象的一样,除了 reloadView 切换实际上并没有重新加载视图。
如果您的数据可以更改,您需要 ForEach
的动态变体。
尝试替换:
List {
ForEach(self.data.database1) { row in
HStack {
...
与:
List {
ForEach(self.data.database1, id: \.id) { row in
HStack {
...
编辑
看起来您的数据在删除项目后并未刷新 - 您是从服务器上删除的,而不是本地删除的。
删除项目后可以重新加载:
func deleteItem(id: Int) {
...
let task = URLSession.shared.dataTask(with: request) { data, response, error in
...
if let data = data {
let payloadAsSimpleString = String(data: data, encoding: .utf8) ?? "(can't parse payload)"
print("Response contains payload\n\(payloadAsSimpleString)")
}
// here you can reload data from the server
// or pass function (which reloads data) as a parameter and call it here
}
task.resume()
}
所以为了简单起见,我将首先描述我的代码的运行方式。我有一个通过使用 ForEach 循环遍历 AWS 数据库生成的列表。
List{
ForEach(self.data.database1){ row in
HStack {
Button("\((row.name)!)") {
self.selectedItem = row.id
self.selectedItemName = row.poi!
self.pressedItem = true
}
Spacer()
Button("Delete") {
self.selectedItem = row.id
self.showDeleteItemView = true
//this brings up a view that can confirm you want to delete
}.buttonStyle(BorderlessButtonStyle())
}
}
}
列表中的每一行都包含一个“删除”按钮。此删除按钮打开如下所示的视图:
if self.showDeleteEventView == true {
ConfirmActionView(showView: self.$showDeleteItemView, actionName: "delete this event", function: {
for item in self.data.database1{
if self.selectedItem == item.id{
DispatchQueue.main.async {
self.data.deleteItem(id: event.id)
self.reloadView.toggle()
}
}
}
}, buttonLabel: "Delete")
}
观点是:
struct ConfirmActionView: View {
@Binding var showView: Bool
var actionName: String
var function: () -> Void
var buttonLabel: String
var body: some View {
ZStack {
VStack {
HStack {
Spacer()
Button("X") {
self.showView = false
}
}
Text("Are you sure you want to \(self.actionName)?")
Spacer()
HStack {
Button("\(self.buttonLabel)") {
print("confirmed action")
self.function()
self.showView = false
}
Button("Cancel") {
self.showView = false
}
.padding(EdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6))
}
}.frame(width: 300, height: 150)
}
}
}
deleteItem() 函数如下:
func deleteItem(id: Int) {
let baseUrl = URL(string: itemUrl)
let deletionUrl = baseUrl!.appendingPathComponent("\(id)")
print("Deletion URL with appended id: \(deletionUrl.absoluteString)")
var request = URLRequest(url: deletionUrl)
request.httpMethod = "DELETE"
print(token) // ensure this is correct
request.allHTTPHeaderFields = ["Authorization": "Token \(token)"]
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Encountered network error: \(error)")
return
}
if let httpResponse = response as? HTTPURLResponse {
// this is basically also debugging code
print("Endpoint responded with status: \(httpResponse.statusCode)")
print(" with headers:\n\(httpResponse.allHeaderFields)")
}
// Debug output of the data:
if let data = data {
let payloadAsSimpleString = String(data: data, encoding: .utf8) ?? "(can't parse payload)"
print("Response contains payload\n\(payloadAsSimpleString)")
}
}
task.resume()
}
stateVariable1 是用于保存行中项目名称的变量。 reloadView 是一个@State 布尔变量,所以我想如果我切换它,视图应该在从数据库中删除项目后刷新。代码的功能与我想象的一样,除了 reloadView 切换实际上并没有重新加载视图。
如果您的数据可以更改,您需要 ForEach
的动态变体。
尝试替换:
List {
ForEach(self.data.database1) { row in
HStack {
...
与:
List {
ForEach(self.data.database1, id: \.id) { row in
HStack {
...
编辑
看起来您的数据在删除项目后并未刷新 - 您是从服务器上删除的,而不是本地删除的。
删除项目后可以重新加载:
func deleteItem(id: Int) {
...
let task = URLSession.shared.dataTask(with: request) { data, response, error in
...
if let data = data {
let payloadAsSimpleString = String(data: data, encoding: .utf8) ?? "(can't parse payload)"
print("Response contains payload\n\(payloadAsSimpleString)")
}
// here you can reload data from the server
// or pass function (which reloads data) as a parameter and call it here
}
task.resume()
}