はじめに
Jetpack Composeでフォーム系UIを書くと、
ほぼ確実に次のようなコードを書きます。
onChange = { value ->
updateModel(value)
}
自分も最初は何も疑っていませんでした。
きっかけ
Edit系画面で次のような実装をしていました。
EditBasicForm(
value = state.model,
onChange = { m ->
state = state.copy(model = m.update())
}
)
見た目は問題なさそうですが、buildが不安定になりました。
起きていた問題
Type mismatch
None of the following candidates is applicable
修正すると別の場所が壊れる
lambdaを少し触るだけで、症状が変わる状態でした。
解決策:lambdaをやめる
EditBasicForm(
value = state.model,
onChange = ::updateModel
)
ViewModel側は次の形にしました。
private fun updateModel(m: Model) {
state = state.copy(
model = m.update(),
error = null
)
}
これで build は安定しました。
なぜこれで解決したのか
lambdaはその場で型推論される
Compose + State + Generics で推論が複雑になる
関数参照はシグネチャが確定している
結果として、型エラーが消えました。
副次的なメリット
ViewModelの責務が明確
UI側が値を渡すだけになる
ロジックが一箇所に集約される
やらなくなったこと
UI側で state.copy を直接書く
lambda内でロジックを書く
「とりあえずlambda」で逃げる
おわりに
lambdaが悪いわけではありません。
ただ、ComposeとState管理が絡む場合は
型を確定させる書き方の方が安全でした。