「View と State を分離する」は Compose 時代でも重要なのか?

Jetpack Compose が普及した今でも、「View と State を分離することは重要ですか?」という質問をよく見かけます。

結論から言うと、重要ではあるものの、設計の中心ではなくなりました。

Compose が登場したことで、私たちが考えるべきことは「View と State を分離すること」から、「State をどこに持つべきか」へと変わっています。

 

🤔 XML 時代は「View と State の分離」が重要だった

従来の Android View システムでは、View は変更可能なオブジェクトでした。

画面を更新するたびに、

- setText()
- setVisibility()
- notifyDataSetChanged()

のような API を呼び出して View を直接変更します。


State
   │
ViewModel
   │
View(XML)

View が多くの状態を抱えていたため、UI の更新処理とビジネスロジックを分離することが、保守性を高めるために非常に重要でした。

 

🤔 Compose は View 自体が状態を持たない

Compose では UI は関数です。


@Composable
fun UserScreen(state: UserState) {
    Text(state.name)
}

state が変われば、Compose が自動的に再コンポーズし、UI を描き直します。

開発者が View を直接更新することはほとんどありません。

つまり、


 State
   │
Composable
   │
  UI

という流れになり、「View をどう更新するか」を意識する場面は大幅に減りました。

その結果、「View と State を分離すること」自体の重要性は相対的に小さくなっています。

 

🤔 公式ドキュメントが強調しているのは State Hoisting

Compose の公式ドキュメントを見ると、「View と State の分離」ではなく State Hoisting が中心テーマになっています。

最初に紹介される原則がこちらです。

State は、それを利用する場所のできるだけ近くに置くべき

これは XML 時代の

「まず ViewModel に置こう」

という発想とは少し異なります。

例えば、1つの Composable だけが利用する状態なら、


var expanded by rememberSaveable {
    mutableStateOf(false)
}

のように Composable の中で保持することが推奨されています。

公式ドキュメントでも、

Keeping UI element state internal to composable functions is acceptable.

と明記されています。

 

🤔 ViewModel は「すべての State の置き場所」ではない

Compose の公式ドキュメントには、さらに興味深い説明があります。

The lowest common ancestor can also be outside of the Composition. For example, when hoisting state in a ViewModel because business logic is involved.

ここで重要なのは、

「ビジネスロジックが関係するから ViewModel に置く」

と説明していることです。

「画面の State はすべて ViewModel に置く」とは書かれていません。

さらに、公式は ViewModel を次のようにも説明しています。

A ViewModel is just an implementation detail of a state holder with certain responsibilities.

つまり ViewModel は、

State Holder の実装方法の一つ

という位置付けです。

もちろん、ViewModel は今でも重要なコンポーネントです。

しかし、Compose の世界では「唯一の State Holder」ではありません。

 

🤔 Compose では「State の寿命」を考える

Compose では State の種類ごとに、適切な置き場所があります。


UIだけで使うState
      │
  remember
      │
rememberSaveable
      │
 Navigation
      │
 ViewModel
      │
 Repository

それぞれ保持できる期間が異なります。

- remember は再コンポーズまで
- rememberSaveable は Configuration Changes や Process Death 後まで
- Navigation は画面遷移に関する状態
- ViewModel は画面のライフサイクルとビジネスロジック
- Repository はアプリ全体のデータ

Compose では、

「この State は ViewModel に置くべきか?」

ではなく、

「この State はどのくらい生き続けるべきか?」

という視点で考える方が自然です。

 

🤔 まとめ

Compose によって、「View と State を分離する」という考え方が間違いになったわけではありません。

ただし、Compose は UI 自体が宣言的になったため、その問題は以前ほど大きくなくなりました。

現在の Android アーキテクチャで重要なのは、

「State をどこに配置するか」

そして

「その State をどのライフサイクルまで保持するか」

です。

実際、Compose の公式ドキュメントも「View と State の分離」ではなく、「State Hoisting」や「State Ownership」を中心に説明しています。

ViewModel を使うことが目的ではなく、State に最適な寿命と責務を与えることが、Compose 時代の設計と言えるでしょう。

 

🤔 参考


Related Categories :  AndroidDevelopmemtJetpackComposeKMPKotlinKotlin Multiplatform MobileRecommended