SwiftUIのonAppearとは?
Overview
onAppear(perform:)
Adds an action to perform before this view appears.
onAppear(実行:) このビューが表示される前に実行するアクションを追加します。
Parameters
action
The action to perform. If action is nil, the call has no effect.
パラメーター アクション 実行するアクション。 action が nil の場合、呼び出しは効果がありません。
Return Value
A view that triggers action before it appears.
表示される前にアクションをトリガーするビュー。
Flutterの経験がある私の感覚では、initState
と同じものだろうなと思ってます。画面が呼ばれたら実行する処理を書いておく。今回は、Firestoreから取得したデータを例に解説します。
summary
使い方の例ですが、今回は、Firestoreからデータを取得したらページが呼ばれたときに全てのデータを表示するロジックを使ってみようと思います。
こんな感じでロジックを持っているクラスを定義します。今回は使うのは、getBooksメソッドです。
import Foundation
import FirebaseFirestore
class BookRepository: ObservableObject {
let db = Firestore.firestore()
@Published var books: [String] = []
func addBook(textValue: String) async {
do {
let ref = try await db.collection("books").addDocument(data: [
"title": textValue,
"createdAt": Timestamp(date: Date())
])
print("Document added with ID: \(ref.documentID)")
} catch {
print("Error adding document: \(error)")
}
}
func getBooks() async {
do {
let snapshot = try await db.collection("books").getDocuments()
books = snapshot.documents.map { document in
document.data()["title"] as? String ?? ""
}
} catch {
print("Error getting documents: \(error)")
}
}
}
getBooksを使うページでは、Listのクロージャの中で、本のタイトルを取得した数だけ表示します。Listには、class modifierの.onAppear
追加して、非同期処理をするので、Task.ini
の中にgetBooksを定義しているクラスをインスタンス化してプロパティを渡しています。
import SwiftUI
struct ReadBookView: View {
@ObservedObject var bookRepository = BookRepository()
var body: some View {
List(bookRepository.books, id: \.self) { book in
Text(book)
}
.onAppear {
Task.init {
await bookRepository.getBooks()
}
}
}
}
struct ReadBookView_Previews: PreviewProvider {
static var previews: some View {
ReadBookView()
}
}
こんな感じで、Viewにデータが表示されます。
これだけだと中途半端なので、追加ページとFirebaseを使う設定をしたファイルのソースコードも記載しておきます。FirebaseのiOS用のSDKを追加したら試してみてください。全部で4ファイルあれば使えます。
追加画面はこんな感じ:
Firestoreのデータはこれ:
アプリのエントリーポイントのページ:
import SwiftUI
import FirebaseCore
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}
@main
struct FirestoreCookBookAppApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
追加ページ:
import SwiftUI
import FirebaseFirestore
struct ContentView: View {
@State var textValue: String = ""
let bookRepository = BookRepository()
var body: some View {
NavigationView {
VStack {
TextField("本を追加", text: $textValue)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: {
Task.init {
await bookRepository.addBook(textValue: textValue)
}
}) {
Text("本を追加")
.bold()
.padding()
.frame(width: 100, height: 50)
.foregroundColor(Color.white)
.background(Color.orange)
.cornerRadius(25)
}
}
.padding()
.navigationTitle("本の追加")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink(destination: ReadBookView()) {
Image(systemName: "book")
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
thoughts
Firestoreのデータを取得して表示したいが、ページが呼ばれたときに、処理を実行するライフサイクルの仕組みを利用する必要があった。この辺知識がまだ足りていないので、知識のinputとoutputを繰り返して理解をしていきたいと思います。
Discussion