【Jetpack Compose】StateFlow でカウンターを作ってみる

Composable 入れ子の更新具合を確認します。

```kotlin
@HiltViewModel
class SampleViewModel @Inject constructor() : ViewModel() {

  private val _count = MutableStateFlow(0)
  val count = _count.asStateFlow()

  fun inc() {
    _count.update { count -> count + 1 }
  }

}
```
[👉 StateFlow の View への公開](https://android.benigumo.com/20210830/expose-stateflow/)

```kotlin
@Composable
fun SampleScreen(
  viewModel: SampleViewModel = hiltViewModel()
) {

  val count: Int by viewModel.count.collectAsState()

  Column(
   Modifier.fillMaxSize(),
   Arrangement.Center,
   Alignment.CenterHorizontally
  ) {
    Text("$count")
    Button(onClick = { viewModel.inc() }) {
      Timber.d("Button composed.")
      Icon(Icons.Filled.Add, null)
    }
  }
  
}
```

何回クリックしても Button の compose は一回。

```text
Button composed.
```

Button 内に影響される Text() を追加する。

```kotlin
@Composable
fun SampleScreen(
  viewModel: SampleViewModel = hiltViewModel()
) {

  val count: Int by viewModel.count.collectAsState()

  Column(
    Modifier.fillMaxSize(),
    Arrangement.Center,
    Alignment.CenterHorizontally
  ) {
    Text("$count")
    Button(onClick = { viewModel.inc() }) {
      Timber.d("Button composed.")
      Icon(Icons.Filled.Add, null)
      Text("$count") // *
    }
  }
  
}
```


クリックするたびに、Button は compose される。

```text
Button composed.
Button composed.
Button composed.
Button composed.
Button composed.
Button composed.
...
```


# ネストした Composable 

```kotlin
@Composable
fun SampleScreen(
  viewModel: SampleViewModel = hiltViewModel()
) {

  val count: Int by viewModel.count.collectAsState()

  Column(
    Modifier.fillMaxSize(),
    Arrangement.Center,
    Alignment.CenterHorizontally
  ) {
    Text("$count")
    ChildA(onClick = { viewModel.inc() })
    ChildB(count, onClick = { viewModel.inc() })
  }

}

@Composable
fun ChildA(onClick: () -> Unit) {

  Button(onClick = onClick) {
    Timber.d("ChildA composed.")
    Icon(Icons.Filled.Add, null)
  }

}

@Composable
fun ChildB(count: Int, onClick: () -> Unit) {

  Button(onClick = onClick) {
    Timber.d("ChildB composed.")
    Icon(Icons.Filled.Add, null)
    Text("$count")
  }

}
```

<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/1119115a-1556-6802-aa73-31b2e00e3ed2.jpeg" width="320"></div>


ChildA は初回のみ compose されます。 ChildA、ChildB どちらのボタンを押しても re-compose されるのは、ChildB のみです。

```
D: ChildA composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
D: ChildB composed.
```

無駄な描画をしない!

すごいです、Jetpack Compose!!

[👉 JakeWharton/timber: A logger with a small, extensible API which provides utility on top of Android's normal Log class.](https://github.com/JakeWharton/timber)
[👉 Jetpack Compose State Guideline. This article presents the information… | by takahirom | Medium](https://medium.com/@takahirom/jetpack-compose-state-guideline-494d467b6e76)
[👉【Jetpack Compose】Icon() や Image() で ImageVector をより便利に使う](https://android.benigumo.com/20220613/jetpack-compose-imagevector/)