7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Android】Jetpack Compose State 完全ガイド

7
Posted at

はじめに

Jetpack Compose を学んでいると、必ずぶつかるのが State(状態)
「なんか remember とか mutableStateOf とかいっぱいあるんだけど⁉」
と感じる人は多い。でも、一度“本質”をつかむと、Compose はめちゃくちゃ気持ちよく書けるようになる。

この記事では、Compose の状態管理をゼロから体系的に解説する。


1. Compose は「宣言的 UI」

まず大前提。

Compose の UI はこう定義できる:

UI = f(state)
UI は「状態」から“自動的に作られる産物”

だから Compose は「UI を直接変更する」必要がない。
状態を変えれば、UI が勝手に変わる。

まるで——
「心の状態を変えたら表情が変わる」
みたいなもの。(ちょっと哲学)


2. State の基本は “mutableStateOf”

Compose で UI 更新をトリガーする最小単位がこれ。

var count by remember { mutableStateOf(0) }
  • mutableStateOf → 監視可能な状態
  • remember → 再コンポーズしても値を保持
  • by → デリゲートで count++ と扱いやすくする

UI はただ状態を読むだけ

Text("Count: $count")

状態を変えると UI が自動で更新

Button(onClick = { count++ }) {
    Text("Add")
}

これが Compose 最大の魔法。
しかも魔法と言いつつ、実際はとてもシステマチック


3. remember と rememberSaveable の違い

関数 持続範囲 用途
remember 再コンポーズ間 UI の一時状態
rememberSaveable 再コンポーズ+画面回転も保持 入力値やフォーム

例:

var text by rememberSaveable { mutableStateOf("") }

スマホを回転しても消えない。
つまり、TextField などには rememberSaveable が超適切。


4. State Hoisting(状態の持ち上げ)は必須テク

Compose の公式デザイン哲学:

UI はできるだけ “状態を持たない” 方がいい。
状態は外(ViewModel)に置く方が健全。

例えばダメな例:

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    ...
}

状態と UI が混ざる → テストしづらい。


正しい書き方:State Hoisting

@Composable
fun Counter(count: Int, onAdd: () -> Unit) {
    Button(onClick = onAdd) { Text("$count") }
}

外部に State を持たせる:

var count by remember { mutableStateOf(0) }
Counter(count, onAdd = { count++ })

UI は純粋関数になる。
Flutter の「状態リフトアップ」もほぼ同じ考え方。


5. ViewModel × StateFlow × Compose の鉄板構成

実プロダクトではほぼこれ一択。

@HiltViewModel
class MainViewModel @Inject constructor() : ViewModel() {
    private val _uiState = MutableStateFlow(0)
    val uiState = _uiState.asStateFlow()

    fun add() { _uiState.value++ }
}

Compose 側:

val count by viewModel.uiState.collectAsState()
Counter(count) { viewModel.add() }

完全に“UI とロジック分離”。
Clean Architecture が自然に成立する。


6. Recomposition(再コンポーズ)は怖くない

よく聞かれる質問:

UI 全部作り直してるの?
パフォーマンス大丈夫なの?

→ 心配不要。

Compose は内部で:

  • 「どの Composable がどの状態を読んだか」
  • 「どこを再コンポーズすればいいか」

自動で依存追跡 している。

だから、パフォーマンスは極めて賢く最小限の再描画になる。


7. Snapshot System(Compose の裏側の天才)

mutableStateOf が変わると snapshot が変更され、
Compose は次のように動く:

  1. 依存している Composable だけを再実行
  2. 再コンポーズの順序や領域を最適化
  3. 不要な更新は全て除外

つまり:

「状態が変わったところだけ UI を更新する最適化エンジン」

これが UI を高速・効率的に保っている。


8. State の種類まとめ

種類 説明 使うタイミング
mutableStateOf 基本の状態 小規模 UI
remember 再コンポーズに耐える 一時変数
rememberSaveable 回転 survive 入力値・フォーム
derivedStateOf 派生値をメモ化 高コスト計算
SnapshotFlow State → Flow ViewModel 連携
LaunchedEffect 副作用管理 API 呼び出しなど
SideEffect UI スレッド副作用 ログなど
DisposableEffect クリーンアップ用 リスナー解除

9. よくある間違いとベストプラクティス

❌ remember を忘れて毎回初期化

→ TextField の内容が消える

❌ 深い Composable に State を置く

→ ロジックと UI が密結合になる

❌ ViewModel も State もない

→ アプリが育たない構造に


10. まとめ

Compose は:

  • UI = 状態の写し鏡
  • 状態が変われば UI が自動更新
  • remember + mutableStateOf が基本
  • 状態は hoist(持ち上げ)て外へ
  • ViewModel + StateFlow で最強
  • 再コンポーズはスマートで高速
  • Snapshot System が裏で全部管理

→ この思想をつかむと Compose が一気に“わかる側”になる。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?