Jetpack ComposeのCompositionLocalを使って下位階層にデータを渡す

Jetpack ComposeにおいてUIの下位階層にデータを渡すには、Composable関数に引数を渡していくのが一般的だと思います。

引数で渡す以外の方法として、CompositionLocal があります。

これの使い方について解説します。

注意事項

先に CompositionLocal に関する注意事項を書いておきます。

CompositionLocal はほとんどケースでは使わなくて良いものです。グローバル変数のように見えるため乱用するとメンテンスが難しくなったりバグを引き起こしやすくなったりする可能性があります。

一部ケースで有用なものですが、使用する際は十分に注意してください。

実装方法

例として、User情報を下位階層に渡したい場合を実装していきます。

まず compositionLocalOf を使ってCompositionLocal のキーを作成します。

型パラメータとして下位階層に渡したい型を指定し、引数の関数にはデフォルトの値を指定します。この例では、もし渡されてなかった場合はエラーにしています。

次に CompositionLocalProvider を使って実際にUserの情報を提供します。

compositionLocalOf で作ったキーに対して provides を使って実態を渡します。分かりにくいですが、providesinfix関数になっていて、 ProvidedValue を生成するようになっています。

最後に渡された値を取得します。

上のようにキーのcurrentからいつでもUserの情報が取得できるようになります。

もし、 CompositionLocalProvider で渡してない場合は、compositionLocalOf で指定したデフォルトが使用されますが、今回はエラーになるようにしています。

提供されてるCompositionLocal

特に意識しなくても使えるようになってる CompositionLocal がいくつかあります。androidx.compose.ui.platform にLocal~みたいな名前で定義されています。

https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/package-summary

よく使いそうなものでいうと、 Contextが取得できる LocalContext や、URLを開くことができる LocalUriHandler があります。

参考

https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal

おまけ

ぼくが思いついた便利な使い方としてはNavigation Composeと組み合わせた使い方です。

まず画面遷移のメソッドを定義したinterfaceをつくります。

CompositionLocal のキーを作ります。

先程のNavigatorを実装したクラスをつくります。

これで準備完了です。

CompositionLocalProvider を使って下位階層で使えるようにします。

で、あとは画面遷移したい箇所で、以下のようにするだけです。

これで引数にNavControllerを渡していかなくてもよくなります。あとは、テストを書くときにダミーのNavigator実装を提供すればテストも書きやすくなります。

AndroidDevChallengeの実装でもやっているので、こちらも参考にしてもらえると良いかもです。

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store