Jetpack Compose で定義される @Composable 関数
Jetpack Compose で定義される @Composable 関数の 引数リスト について@Composable
UI を宣言的に描くための関数に付ける注釈(アノテーション)。
返り値は持たず(Unit)、引数=状態をもとに UI を“宣言”します。
Compose ランタイムが、状態の変化を検知すると 再コンポーズ(recomposition) を行い、必要な部分だけ UI を再生成します。
重要な基本ルール
Composable は Composable からしか呼べない
→ 「@Composable invocations can only happen…」エラーはここが原因。
UI は副作用なしで書く(=同じ入力→同じ出力)
→ 重い処理や I/O は直接書かず、LaunchedEffect などの 副作用 API を使う。
状態は上位で持ち、下位へ渡す(State hoisting)
→ UI は純粋に“表示”だけを担当し、値更新はコールバックで親/VM に委譲。
再コンポーズ & 状態管理のキホン
Compose は 状態(State) が変わると、その状態を読んでいる Composable 範囲だけを再実行します。
よく使う状態:
remember { mutableStateOf(...) } … コンポーズの間だけ保持
rememberSaveable { ... } … 画面回転などでも保持
collectAsState() … Flow/StateFlow を UI にブリッジ
計算コストの高い派生値には derivedStateOf { ... } を。
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) } // 状態
Button(onClick = { count++ }) {
Text("Count: $count") // 状態を読むので、count 変化でここだけ再コンポーズ
}
}
副作用 API(Side-Effect)
UI 関数内でネットワークや DB を直接叩かない。以下を使います:
LaunchedEffect(key):Key が変わった時だけコルーチンを起動
DisposableEffect(key):登録/解除が必要なリスナー等
SideEffect:フレーム毎に 1 回(例:外部オブジェクトへ通知)
rememberCoroutineScope():ユーザー操作でコルーチン起動
@Composable
fun Screen(userId: Long, viewModel: MyVm = viewModel()) {
val uiState by viewModel.state.collectAsState()
// 初回 or userId 変更時だけ実行
LaunchedEffect(userId) {
viewModel.load(userId)
}
// UI は副作用を書かない
Text(uiState.name)
}
【パラメータ設計(単方向データフロー)】
● **入力(状態)**は引数で受け取る
● **出力(イベント)**はコールバックで返す
よくあるエラーの原因と回避
@Composable エラー
→ Composable 以外(例:onClick の中じゃない外)で Composable を呼んでいないか?
combinedClickable 赤線
→ foundation の opt-in が必要。
import androidx.compose.foundation.ExperimentalFoundationApi
@OptIn(ExperimentalFoundationApi::class) を その関数に付ける。
それでも消えない場合は 依存バージョンの不一致が多いので、clickable への置換も選択肢。
LaunchedEffect は Composable の外で使えない
→ 必ず Composable の本文内で呼ぶ。ドロワーを閉じるなら rememberCoroutineScope().launch { drawerState.close() } を使う。
● AlertDialog( onDismissRequest = on******,******
AlertDialog は Jetpack Compose が用意している組み込みの Composable なので、
パラメータ名(引数の名前)は ライブラリ側で決められていて固定
● OutlinedTextField も Jetpack Compose の組み込み Composable なので、
引数名はあらかじめ決められている。
定義のイメージ
@Composable
fun OutlinedTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
...
)
使い方の例
var childText by remember { mutableStateOf("") }
OutlinedTextField(
value = childText,
onValueChange = { childText = it }, // 入力が変わったときの処理
label = { Text("子カテゴリ名") },
modifier = Modifier.fillMaxWidth()
)
value → テキストフィールドに表示する文字列(状態をバインドする)。
onValueChange → ユーザー入力があったときに呼ばれる処理。
childText = it と書けば、入力値で状態が更新される。
label → 枠の上に表示されるラベル(任意)。
つまり onValueChange = { childText = it } は、ユーザーが文字を入力するたびに childText に入力内容を代入して、UI を再描画させている