目的
JetPack Composeで状態を保存するために用意されている"remember"ですが、これをRememberできない僕の脳のデバッグのために記事を書きます
この記事でわかること
- rememberとは
- remember(ステートフル)のメリットさん
知っておいてほしいこと
-
コンポーザブルのライフサイクル
- 初回コンポーズによってコンポジションが作成されること
- コンポジションとはUIが記述された箱のようなものであること
- 再コンポーズでコンポーザブル関数を再度起動し、コンポジションを更新すること
- ステートフル、ステートレスについて
- ステートフル: 状態を保持しているという制約
- ステートレス: 状態を保持しないという制約
remember とは
コンポーズ可能な関数は、remember コンポーザブルを使用して、単一のオブジェクトをメモリに保存できます。初回コンポーズの際に、remember によって計算された値がコンポジションに保存され、保存された値は再コンポーズの際に返されます。remember を使用すると、可変オブジェクトと不変オブジェクトの両方を保存できます。
要するにどういうこと?
- コンポジション内で保持しておける値
- 再コンポーズが起こっても、それに耐えうる値
- コンポジション内に保持しておけるということは、コンポジションが終了(構成の変更など)したら破棄される
- それに耐える
rememberSaveable
というものもある
- それに耐える
rememberSaveable は、Bundle に保存可能なすべての値を自動的に保存します。その他の値については、カスタムのセーバー オブジェクトに渡すことができます。
ふむふむ、コンポジションという関数があったとして、rememberはその内部変数的な立ち位置的な感じかな?
いやー、でもなー。それだと
- テストとかも書きにくそうだしなぁ
- 内部的な値だから外部から手が出しづらそうだなぁ
- 内部変数だからどこで値が変化したか追わなきゃいけないなぁ
せや!
viewModelみたいに外部で値を監視すればいいのでは?
・・・まあ、言いたいことはわかるんですが
こんなコードで使えます
@Composable
fun HelloContent() {
Column(modifier = Modifier.padding(16.dp)) {
var name by remember { mutableStateOf("") }
if (name.isNotEmpty()) {
Text(
text = "Hello, $name!",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
}
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Name") }
)
}
}
- OutlinedTextFieldで入力を検知し、nameに代入する
- nameが空でなければ、Textを表示する
ざっとこんな流れで表示されることになる。
全てがこの関数の中で完結していて、nameの値を監視する必要もなければ、外部でいじる必要もないことがわかる
世界から切り離されてて管理が楽っぽい?(ように見える)
←結論←結論←結論←結論←結論
rememberは外部から切り離されている場合において有効
基本的にはステートフルなこの形ではなく、ステートレスな形で外側に状態を持たせた方が管理がしやすい
ただrememberするべきなのは、rememberをあえて使うという道
内部だけで処理が終わる場合、その関数を丸ごと切り出せて管理が嬉しいかもよという話
心の片隅にRemember "remember"