
etpack Composeで階層が深くなると発生する「バケツリレー(Prop Drilling)」。
「自分(中間コンポーネント)は使わないのに、孫に渡すためだけに引数を定義する」という不毛な作業は、CompositionLocal でスマートにショートカットしましょう。
🧑🏻💻 1. CompositionLocal の仕組み
通常、データは「親 → 子 → 孫」と引数で手渡ししますが、CompositionLocal はツリー全体にデータを「漂わせる」イメージです。
下の階層にいるコンポーネントは、必要なときにそのデータを「キャッチ」するだけで済みます。
🧑🏻💻 2. 実装例:2つのデータ(名前と色)を孫まで飛ばす
「ユーザー名」と「テーマカラー」の2つのデータを、中間の「子」を介さずに「孫」へ届けます。
① データの「鍵」を定義する
まず、共有したいデータの種類ごとに CompositionLocal オブジェクトを作成します。
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
// 1. 各データの「鍵」を作成(デフォルト値を設定)
val LocalUserName = staticCompositionLocalOf { "ゲスト" }
val LocalUserColor = staticCompositionLocalOf { Color.Black }
② 親・子・孫の実装
中間の ChildView が引数を一つも受け取っていない点に注目してください。
@Composable
fun ParentScreen() {
val name = "桃太郎"
val brandColor = Color(0xFFFF5722) // オレンジ
// 2. CompositionLocalProvider で値を注入(複数一気に指定可能)
CompositionLocalProvider(
LocalUserName provides name,
LocalUserColor provides brandColor
) {
// 子を呼び出す(引数で渡す必要なし!)
ChildView()
}
}
// --- 中間のコンポーネント ---
@Composable
fun ChildView() {
// 自身はデータを使わないので、引数も処理もスッキリ!
println("ChildView: 私は何も知りません。")
GrandChildView()
}
// --- データの使い道がある末端(孫) ---
@Composable
fun GrandChildView() {
// 3. .current を使って必要なデータだけを直接取得
val name = LocalUserName.current
val color = LocalUserColor.current
Column {
Text(text = "こんにちは、${name}さん!", color = color)
Text(text = "親から直接データを受け取りました。")
}
}
🧑🏻💻 3. なぜ「2方向」でも楽なのか?
バケツリレーの場合、渡す項目が「名前」「色」「権限」「ID」と増えるたびに、ルートから末端までの全関数の引数を書き直す必要があります。
CompositionLocal なら:
親: provides を追加するだけ
子: 修正不要(ここが最大のメリット!)
孫: .current で取り出すだけ
🧑🏻💻 4. 注意点:使いすぎに注意!
魔法のように便利な CompositionLocal ですが、使いすぎると「このコンポーネントは何に依存しているのか?」がコードから読み取りにくくなります。
推奨: アプリ全体のテーマ(色・フォント)、ログインユーザー情報、ロケール設定など。
非推奨: その画面内の特定のボタンでしか使わないような一時的なフラグ。
バケツリレーが3階層を超え、中間コンポーネントが「ただの運び屋」になっていたら、CompositionLocal への切り替え時かもしれません。
Related Categories : Android・JetpackCompose・Kotlin・Newbie・Trending