実現したいこと
以下のすべてを解決、またはバランスよく実装したい。
- 入力要素が3つ以上あるとき、状態管理用の変数が2重、3重、4重管理になることを防ぎたい(あるいはグループ化して管理したい)。
- 入力要素のかくつきをなくしたい(あるいは抑えたい)
前提
KMP(Kotlin Multiplatform)を使用しています。
まずはWindows(デスクトップ向け)のUI要素を作成しているのですが、Android向けのjetpack composeの際に遭遇した問題に再び差し当たっています。
その際はxmlで回避できましたが、今回はUIフレームワークがCompose一択で困っています。
質問の内容を詳しく書いてください。
1の問題について
愚直にやるのであれば、以下のような状態になるかと思います。
kotlin
1@Composable 2fun TestScreen() { 3 val viewModel = remember { MyViewModel() } 4 5 val nameState by viewModel.nameFlow.collectAsState() 6 val emailState by viewModel.emailFlow.collectAsState() 7 8 Column { 9 Text(text = nameState) 10 TextField( 11 value = nameState, 12 onValueChange = { newValue -> 13 viewModel.updateName(newValue) 14 } 15 ) 16 17 TextField( 18 value = emailState, 19 onValueChange = { newValue -> 20 viewModel.updateEmail(newValue) 21 } 22 ) 23 } 24} 25 26class MyViewModel { 27 private val _nameFlow = MutableStateFlow("") 28 val nameFlow: StateFlow<String> = _nameFlow.asStateFlow() 29 30 private val _emailFlow = MutableStateFlow("") 31 val emailFlow: StateFlow<String> = _emailFlow.asStateFlow() 32 33 fun updateName(newName: String) { 34 _nameFlow.value = newName 35 } 36 37 fun updateEmail(newEmail: String) { 38 _emailFlow.value = newEmail 39 } 40}
この状態ですと、
kotlin
1 private val _nameFlow = MutableStateFlow("") 2 val nameFlow: StateFlow<String> = _nameFlow.asStateFlow()
の様な部分に関してTextFieldが増えるたびにこの記述が1つ増え、さらには@Composable内での変数も追加しなければならず、今後、ロジックが増えるごとにそのロジックにも同じ記述が増えることを懸念しておりこれを可能な限り回避または共通化したいです。
2の問題について。
1の問題を回避するプラス、入力フォームのグループ化の意味合いを強めるためにDataClassを追加しMutableStateFlowでラップするとすると以下のようなコードになるかと思います。
Kotlin
1 2@Composable 3fun TestScreen() { 4 val viewModel = remember { MyViewModel() } 5 6 7 val uiState by viewModel.uiState.collectAsState() 8 9 // remember or derivedStateOf 10 val nameState = remember(uiState) { uiState.name } 11 val emailState = remember(uiState) { uiState.email } 12 13 Column { 14 Text(text = nameState) 15 TextField( 16 value = nameState, 17 onValueChange = { newValue -> 18 viewModel.updateName (newValue) 19 } 20 ) 21 22 TextField( 23 value = emailState, 24 onValueChange = { newValue -> 25 viewModel.updateEmail (newValue) 26 } 27 ) 28 } 29} 30 31data class TestForm( 32 val name: String, 33 val email: String, 34) 35 36class MyViewModel { 37 private val _uiState = MutableStateFlow(TestForm(name = "", email = "")) 38 val uiState: StateFlow<TestForm> = _uiState.asStateFlow() 39 40 fun updateName(newName: String) { 41 _uiState.value = _uiState.value.copy(name = newName) 42 } 43 44 fun updateEmail(newEmail: String) { 45 _uiState.value = _uiState.value.copy(email = newEmail) 46 } 47}
しかしこの方法ですと、composeが再コンポーズされる、またはその判定の計算のせいか操作のかくつきが若干増えることがネックになります。
発生している問題
以上の状態をどのように回避すればよいのでしょうか?
TextFieldがたくさんあるという状態をそもそも想定していなかったりするのでしょうか。
よろしくお願いいたします。
調べた内容
Stateはcomposable関数内でしか意味をなさないようで、viewModelにコールバック関数を仕込み共通化するのは不可能でした。
多数の入力がある際のサンプルが見つかりませんでした。
compose for desktopのプラグインを導入し、実施している都合からかIDEからサンプルなどは参照できなそうでした。
再コンポーズの条件に関しては以下の内容を確認しました。
https://qiita.com/wcaokaze/items/a066ab81b69578390992
補足情報
不足があれば追記致します。
またこれらの問題に関してコミュニティなどがあれば、

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。