通过更改 SwiftUI 中的 @State 变量来刷新视图不起作用
Posted
技术标签:
【中文标题】通过更改 SwiftUI 中的 @State 变量来刷新视图不起作用【英文标题】:Refreshing view by changing @State variable in SwiftUI not working 【发布时间】:2020-08-12 22:10:25 【问题描述】:所以为了简单起见,我将首先描述我的代码的运行方式。我有一个使用 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 部分)。 @pawello2222 嗨,pawello,我添加了包含 ForEach 的列表。如果您需要我添加 deleteItem() 函数,请告诉我 你试过ForEach(self.data.database1, id: \.id) row in
吗?还是id: \.self
?
@pawello2222 你的意思是用 if 语句代替 for 循环?不,我没有,很抱歉,我不知道该放在哪里。
【参考方案1】:
如果您的数据可以更改,您需要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()
【讨论】:
我尝试替换它-确认删除时视图的刷新没有变化。 如果我添加 deleteItem() 函数会有帮助吗? 我添加了您要求的所有内容。我知道这很多,但我试图解释和注释什么是重要的。非常感谢您,如果您能帮助我,我将永远感激不尽,哈哈 @nickcoding 所以在deleteItem
中,您向服务器发送请求以删除您的项目。但看起来您不再查询数据(self.reloadView.toggle()
不会做任何事情)。我建议您在删除项目后重新加载数据(因为它是异步的,您可能需要回调)。
@nickcoding 我用额外的步骤更新了我的答案。以上是关于通过更改 SwiftUI 中的 @State 变量来刷新视图不起作用的主要内容,如果未能解决你的问题,请参考以下文章
当从 GeometryReader 中进行更改时,SwiftUI 不会反映对 @Binding @State 变量的更改
如何根据 SwiftUI 中的 @State 更改导航视图的导航视图样式?
如何在 SwiftUI 中使用 UIButton 更改 @State var