😇
Flutter initState & setState -> SwiftUI ???
対象者
- SwiftUIに興味がある人
- 他のFWでライフサイクルを学んだ人
最近、副業でSwiftUIを使っています。FlutterやReactと同じように、宣言的UIと呼ばれ、コードを書くだけで、イメージしたUIを再現できるFWなのだなと思いつつまだまだ理解が足りないので普段から、自己学習をしています。
プロジェクトの説明
Flutter & React.js で書いたコードを SwiftUIに置き換えて、ページが呼ばれた時の処理と画面を更新するだけの処理ですが、理解しながら、覚えていこうと思います。
Flutterの場合だと、ページが呼ばれたタイミングで、initState
を実行し、一度だけ処理を実行。ボタンを押すと、setState
で画面を更新するライフサイクルが実行されます。
Flutterの場合
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool isLoading = false;
int count = 0;
// count++
void increment() {
setState(() {
count++;
});
}
// 3秒カウントするログを出す
void startCount() {
setState(() {
isLoading = true;
});
Future.delayed(const Duration(seconds: 3), () {
setState(() {
isLoading = false;
count++;
});
});
}
void initState() {
// 画面が表示された時に3秒カウントを開始する
startCount();
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Page'),
),
body: Center(
child: isLoading
? const CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: increment,
child: const Text('Start Count'),
),
],
),
),
);
}
}
Reactの場合だと、 ブラウザに、ページが表示されたら、useEffect
の中の処理を実行し、ボタンを押すイベントが実行されると、useState
で画面を更新します。
Reactの場合
import React, { useState, useEffect } from "react";
export default function App() {
return (
<div className="App">
<HomePage />
</div>
);
}
function HomePage() {
const [isLoading, setIsLoading] = useState(false);
const [count, setCount] = useState(0);
// count++
const increment = () => {
setCount((prevCount) => prevCount + 1);
};
// 3秒カウントする
const startCount = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setCount((prevCount) => prevCount + 1);
}, 3000);
};
// 画面が表示された時に3秒カウントを開始する
useEffect(() => {
startCount();
}, []);
return (
<div style={{ textAlign: "center" }}>
<h1>Home Page</h1>
<div>
{isLoading ? (
<p>Loading...</p>
) : (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Start Count</button>
</div>
)}
</div>
</div>
);
}
SwiftUIの場合だと、ページが呼ばれたときは、.onAppear
で処理を実行する。ボタンを押すイベントが起きた時に、画面を更新するときは、@State
を使う。
SwiftUIの場合
import SwiftUI
struct ContentView: View {
@State private var isLoading = false
@State private var count = 0
var body: some View {
NavigationStack {
ZStack {
if isLoading {
ProgressView()
} else {
VStack {
Text("Count: \(count)")
Button("Start Count") {
increment()
}
}
}
}
.navigationTitle("Home Page")
}
.onAppear {
startCount()
}
}
func increment() {
count += 1
}
func startCount() {
isLoading = true
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
isLoading = false
count += 1
}
}
}
感想
ざっくりとですけど、ライフサイクルは似ていることを解説しました。同じようなFWやライブラリを知っていれば、プログラミング言語のルールを覚えるだけなので、そんなには、難しくはないかもしれません。
- ページが呼ばれたとき
- 画面が更新される
- 状態を破棄する
setState
& useState
-> @State
initState
& useEffect
-> onAppear
Discussion