👏

SwiftUI リストに値を追加してUIを更新する LocalState

2023/08/18に公開

参考サイト
https://zenn.dev/ueshun/articles/2b26aaad40d6a3#id=local-state

まずボタンを押しても動かなかったサンプルコード

import SwiftUI

struct GoodByeUIKitApp2: View {
    private var fruits = ["りんご", "オレンジ", "バナナ"]
    var body: some View {
        Button("押すとリストが更新されなかった", action: {
            fruits.append("ナシ")
        })
        List {
            ForEach(0 ..< fruits.count) { index in
                Text(fruits[index])
            }
        }
    }
}

@main
struct GoodByeUIKitApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            GoodByeUIKitApp2() // 一番最初に表示されるView: これから作成します
        }
    }
}


原因1

@Stateを状態の変数の先頭につける

 @State private var fruits = ["りんご", "オレンジ", "バナナ"]

Dart(Flutter)の場合、final変数でもlistの場合はappend出来てしまうので非常に便利だと思った。

原因2

明示的な id の指定: ForEach 内で id パラメータを指定することで、要素の一意性が保証され、更新が正しく行われる

   ForEach(fruits.indices, id: \.self) { index in
        Text(fruits[index])
    }

動作する全コード

import SwiftUI

struct GoodByeUIKitApp2: View {
    @State private var fruits = ["りんご", "オレンジ", "バナナ"]
    var body: some View {
        Button("動作するコード", action: {
            fruits.append("ナシ")
        })
        List {
            ForEach(0 ..< fruits.count) { index in
                Text(fruits[index])
            }
        }
    }
}

@main
struct GoodByeUIKitApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            GoodByeUIKitApp2() // 一番最初に表示されるView: これから作成します
        }
    }
}

次回はこのコードはShared Stateを使用する。

Discussion