LaunchedEffectなどでよく使うsnapshotFlow。
見た目がdistinctUntilChanged()と似ていて、「どちらも重複を弾くのでは?」と思ったことはありませんか。
実は似ているようで、扱う世界がまったく異なります。
この記事では、両者の違いと使い分けを簡潔に整理します。
結論:見ている世界が違う
観点 | snapshotFlow | distinctUntilChanged |
---|---|---|
対象 | ComposeのState | Flowの値 |
判定基準 | Stateの再読み取りと等価チェック | equals()による同一判定 |
主な用途 | Compose → Flow変換 | Flow内の重複除去 |
- snapshotFlowは「Composeの再読み取り」をトリガーにFlowをemitします。
- distinctUntilChangedは「Flowの連続した値が同じならスキップ」します。
前者はComposeの世界、後者はFlowの世界で動作します。
snapshotFlowとは
snapshotFlow
は、ComposeのState
やderivedStateOf
をFlowに変換するAPIです。
snapshotFlow { uiState.value }
Composeの再compose時に、このブロック内で読み取られているStateが変わるとFlowに値をemitします。
内部的にはequals()で比較しているわけではなく、Composeのスナップショットシステムが「Stateに変更があった」と判断したときにemitします。
つまり、snapshotFlowはComposeの状態管理の仕組みに基づいて動作します。
distinctUntilChangedとは
distinctUntilChanged()は、Kotlin Flowの標準演算子です。
Flowの中で、前回とequals()で同じ値が続く場合、その値をスキップします。
flowOf(1, 1, 2, 2, 3)
.distinctUntilChanged()
// => 1, 2, 3 が流れる
Composeとは無関係に、Flowの中の値の同一性だけを見ています。
両方使うと便利なケース
たとえば、uiState.listがlistOf(...)で毎回新しいインスタンスを返す場合。
snapshotFlow { uiState.list }
.distinctUntilChanged()
snapshotFlowだけでは、リストが毎回新しい参照になるため、毎回emitされます。
このとき.distinctUntilChanged()を追加すると、中身が同じならスキップされます。
- snapshotFlowで「Composeの状態変化」を拾う
- distinctUntilChangedで「値の重複」を防ぐ
この組み合わせは実務でもよく使われます。
まとめ
目的 | 適したAPI |
---|---|
ComposeのStateをFlowに変換したい | snapshotFlow |
Flow内の連続した重複値を除きたい | distinctUntilChanged |
両方やりたい | snapshotFlow { … }.distinctUntilChanged() |