簡體   English   中英

從 StateFlow 收集 state

[英]Collect state from StateFlow

我在 Compose 和 MVVM 架構中開發應用程序。 我有每個屏幕的視圖 state 的 viewModel。 視圖模型:

class ProfileViewModel : ViewModel() {

    private val _state = MutableStateFlow(ProfileViewState())
    val state: StateFlow<ProfileViewState> get() = _state

    val actions = Channel<ProfileAction>()

    init {
        viewModelScope.launch {
            combine(_state) {
                ProfileViewState()
            }.collect {
                _state.value = it
            }
    }
}

State:

class ProfileViewState {
    val nick: MutableStateFlow<String> = MutableStateFlow("default nick")
}

當用戶按下按鈕時,我會更改 state 中“nick”的值。

_state.value.nick.value = "new nick"

我想在我的視圖中觀察 state 並在它們更改時自動更新數據

@Composable
fun ProfileScreen() {
        val viewModel: ProfileViewModel = viewModel()
        val viewState by viewModel.state.collectAsState()
}

TextView 我嘗試在其中顯示“nick”值

Text(text = viewState.nick.value, style = MaterialTheme.typography.h4)

問題是當我更改 state 中的數據時,屏幕沒有反應也沒有更新。 當我打開 ProfileScreen 時,我得到了具有默認值的相同 state(?) 實例

對於簡單的情況,您可以在MutableStateFlow中使用mutableStateOf("default nick")而不是ProfileViewState

就像是:

class ProfileViewState {
    var nick  by mutableStateOf("default nick")
}

在你的可組合物中:

  Text(text = viewState.value.nick, style = MaterialTheme.typography.h4)
  Button(onClick = { viewState.value.nick= "new nick"}){Text("Update")}

如果你想使用MutableStateFlow你必須觀察nick
就像是:

val nick = viewModel.state.value.nick.collectAsState()

Text(text = nick.value, style = MaterialTheme.typography.h4)
Button(onClick = { viewModel.state.value.nick.value  = "new nick"}){Text("Update")}

在這種情況下,您還可以在 viewModel 中提供 function 來更新昵稱:

class HelloViewModel : ViewModel() {
    //...
   
    fun onNameChange(newName: String) {
        _name.value = newName
    }
}

class ProfileViewState {

    val nick: MutableStateFlow<String> = MutableStateFlow("default nick")
   
    fun onNickChange(newNick: String) {
        nick.value = newNick
    }
}

然后在你的可組合中使用:

Button(
     onClick = { viewModel.onNickChange("new nick2")}
){ /*..*/ }

這可能是因為您正在使用嵌套的StateFlow並且只收集外部的,同時更新內部的。 我建議轉到以下實現:

data class ProfileViewState(val nick: String, ...)

// Update it like:
fun updateNick(nick: String){
     _state.value = _state.value.copy(nick = nick)
}

這樣viewModel.state.collectAsState()應該可以工作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM