Kotlinのrememberについて

採用はこちら

Kotlinそのものというより、Jetpack Compose において remember は「状態管理」を理解するうえで欠かせない存在です。

単なるユーティリティ関数ではなく、再コンポーズ(recomposition)というCompose特有の仕組みと密接に結びついたAPIです。

本記事では、

  1. なぜ remember が必要なのか
  2. remember の基本的な役割
  3. 再コンポーズとの正しい関係
  4. mutableStateOf との役割分担
  5. rememberSaveable との違い
  6. キー付き remember
  7. よくある誤解と注意点

という流れで、実務で使っても破綻しない理解を目指して解説します。

目次

なぜ remember が必要なのか

Jetpack Composeは 宣言的UI を採用しています。

つまり、

「現在の状態がこうであれば、UIはこうなるべき」

という関係をコードで表現します。

この設計では、状態が変わるたびに Composable関数が再評価(再コンポーズ)される ことが前提になります。

再コンポーズで起きる問題

次のコードを見てください。

@Composable
fun Counter() {
    var count = 0
    Button(onClick = { count++ }) {
        Text("$count")
    }
}

このコードが期待通り動かない理由は、実は 2つ あります。

問題①:count は Compose の State ではない

count は単なるローカル変数なので、count++ しても Compose は変更を検知できません。

そのため、通常は 再コンポーズ自体が発生しません

問題②:再コンポーズが起きた場合は必ず初期化される

仮に他のState変更などで再コンポーズが発生すると、Composable関数は再評価されるため、count は再び 0 に初期化されます。

再コンポーズをまたいで値を保持し、かつ変更をUIに反映させる仕組みが必要

ここで remember が登場します。

remember の基本的な役割

remember の役割を一言でまとめると、

Composableが再評価されても、値を保持し続けるための仕組み

です。

基本形は次の通りです。

val value = remember { 初期化処理 }

この {} の中の処理は、

  • 初回のコンポーズ時に評価される
  • 再コンポーズ時には前回保持していた値が再利用される

という挙動になります。

再コンポーズと remember の正しい関係

Composeでは、Stateの変更などをきっかけに 再コンポーズが発生する可能性 があります。

重要なのは、

  • 再コンポーズ = 必ず関数全体が毎回実行される
    ではない、という点です。

Composeは最適化により、変更の影響がない部分の再評価を スキップ することがあります。

ただし概念的には、

  • 再コンポーズでは 同じComposableが再評価される可能性がある
  • remember はその再評価をまたいで値を保持する

と理解しておくと、実務上の齟齬は起きにくくなります。

remembermutableStateOf の役割分担

この2つはセットで語られることが多いですが、役割は明確に異なります。

API役割
remember値を再コンポーズ間で保持する
mutableStateOf値の変更をComposeに通知し、再コンポーズを促す

正しい組み合わせ例

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

    Button(onClick = { count++ }) {
        Text("$count")
    }
}
  • remember によって count の値は保持される
  • mutableStateOf によって count の変更がStateとして監視される

この2つが揃って初めて、「状態として正しく振る舞うUI」になります。

remember が使える範囲と注意点

remember は Composable の中専用

fun foo() {
    val x = remember { 10 } // ❌ コンパイルエラー
}

rememberComposableのライフサイクルに結びついたAPI のため、@Composable 関数の外では使用できません。

ViewModelの代替にはならない

remember で保持される値は、

  • ComposableがCompositionに存在している間のみ有効

です。

そのため、

  • 画面回転
  • ナビゲーションで画面が破棄された場合
  • プロセスキル

などでは 値は失われます

画面やアプリ全体で共有・保持すべき状態は ViewModel を使います。

rememberSaveable との違い

rememberSaveableremember の拡張版です。

挙動の違い

API再コンポーズ画面回転
remember保持される失われる
rememberSaveable保持される保持される
var count by rememberSaveable { mutableStateOf(0) }

rememberSaveable は、

  • プリミティブ型や Parcelable など
  • 「保存可能なUI状態」

を自動的に保存・復元します。

※ これは Composable内のUI状態向け の仕組みであり、ViewModelの SavedStateHandle とは用途・責務が異なります。

キー付き remember

remember にはキーを指定できます。

val user = remember(userId) {
    loadUser(userId)
}

この場合、

  • userId が同じ → 以前の値を再利用
  • userId が変わる → 初期化処理が再実行

という挙動になります。

依存関係のあるデータのキャッシュ に非常に有効です。

よくある誤解と注意点

誤解①:remember は永続的に保存される

❌ 永続ではありません
⭕ Composableのライフサイクル内のみ有効

誤解②:remember は状態管理の万能解

❌ 画面をまたぐ状態・ビジネスロジックには不向き
⭕ UIに近い一時的な状態向け

誤解③:remember は必ず mutableStateOf とセット

❌ 必ずではない
⭕ 重いオブジェクトの生成結果をキャッシュする用途でも使われる
(ただしライフサイクル理解が必須)

まとめ

最後に整理します。

状態の種類適切な選択
一時的なUI状態remember
回転でも保持したいUI状態rememberSaveable
画面・ロジックをまたぐ状態ViewModel

remember は「再コンポーズを安全に跨ぐための仕組み」であり、Composeの状態管理を成立させるための基礎です。

以上、Kotlinのrememberについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次