android - Jetpack Compose 状态提升、预览和 ViewModels 最佳实践

标签 android kotlin state android-jetpack-compose android-jetpack-compose-preview

因此,在 Jetpack Compose 中似乎推荐的做法是从您的可组合项中提升状态,使它们成为无状态、可重用和可测试的,并允许在预览中轻松使用它们。
所以而不是有类似的东西

@Composable
fun MyInputField() {
    var text by remember { mutableStateOf("") }
    TextField(value = text, onValueChange = { text = it })
}
你会像这样提升状态
@Composable
fun MyInputField(text: String, onTextChange: (String) -> Unit) {
    TextField(value = text, onValueChange = onTextChange)
}
这很好,但是一些更复杂的用途呢?
假设我有一个由可组合对象表示的屏幕,在 View 和 ViewModel 之间有多个交互。该屏幕被分成多个内部可组合项(例如,一个用于标题,一个用于正文,然后又分为几个较小的可组合项)
  • 您不能在可组合内创建 ViewModel(至少使用 viewModel(),您可以手动实例化一个)并在 Preview 中使用此可组合(预览不支持创建这样的 View 模型)
  • 在内部可组合项中使用 ViewModel 会使它们成为有状态的,不是吗?

  • 所以我看到的“最干净”的解决方案是仅在最高可组合级别实例化我的 View 模型,然后仅传递给子可组合 val s 代表状态,以及对 ViewModel 函数的回调。
    但这很疯狂,我不会通过单个参数将我的所有 ViewModel 状态和函数传递给所有需要它们的可组合组件。
    将它们分组到 data class例如可能是一个解决方案
    data class UiState(
      val textInput: String,
      val numberPicked: Int,
      ……
    
    也许为回调创建另一个?
    但这仍然是创建一个全新的类,只是为了模仿 View 模型已经拥有的东西。
    我实际上并没有看到这样做的最佳方法是什么,而且我在任何地方都没有找到任何相关信息

    最佳答案

    管理复杂状态的一个好方法是将所需的复杂行为封装到一个类中并使用记住功能,同时尽可能拥有无状态小部件,并在需要时更改状态的任何属性。SearchTextField是一个只使用状态提升的组件,SearchBar有返回箭头和 SearchTextField而且它本身也是一个无状态的可组合。这两者和 Searchbar 的父级之间的通信仅通过回调函数处理,这使得 SearchTextField 可以重新使用并且易于预览,并在预览中具有默认状态。 HomeScreen包含此状态以及您管理更改的位置。
    完整实现是posted here .

    @Composable
    fun <R, S> rememberSearchState(
        query: TextFieldValue = TextFieldValue(""),
        focused: Boolean = false,
        searching: Boolean = false,
        suggestions: List<S> = emptyList(),
        searchResults: List<R> = emptyList()
    ): SearchState<R, S> {
        return remember {
            SearchState(
                query = query,
                focused = focused,
                searching = searching,
                suggestions = suggestions,
                searchResults = searchResults
            )
        }
    }
    
    请记住保持状态的功能,仅在合成期间对其进行评估。
    class SearchState<R, S>(
        query: TextFieldValue,
        focused: Boolean,
        searching: Boolean,
        suggestions: List<S>,
        searchResults: List<R>
    ) {
        var query by mutableStateOf(query)
        var focused by mutableStateOf(focused)
        var searching by mutableStateOf(searching)
        var suggestions by mutableStateOf(suggestions)
        var searchResults by mutableStateOf(searchResults)
    
        val searchDisplay: SearchDisplay
            get() = when {
                !focused && query.text.isEmpty() -> SearchDisplay.InitialResults
                focused && query.text.isEmpty() -> SearchDisplay.Suggestions
                searchResults.isEmpty() -> SearchDisplay.NoResults
                else -> SearchDisplay.Results
            }
    }
    
    并通过将状态传递给其他可组合或 ViewModel 来更改 UI 任何部分的状态
    fun HomeScreen(
        modifier: Modifier = Modifier,
        viewModel: HomeViewModel,
        navigateToTutorial: (String) -> Unit,
        state: SearchState<TutorialSectionModel, SuggestionModel> = rememberSearchState()
    ) {
    
    
        Column(
            modifier = modifier.fillMaxSize()
        ) {
                
            SearchBar(
                query = state.query,
                onQueryChange = { state.query = it },
                onSearchFocusChange = { state.focused = it },
                onClearQuery = { state.query = TextFieldValue("") },
                onBack = { state.query = TextFieldValue("") },
                searching = state.searching,
                focused = state.focused,
                modifier = modifier
            )
    
            LaunchedEffect(state.query.text) {
                state.searching = true
                delay(100)
                state.searchResults = viewModel.getTutorials(state.query.text)
                state.searching = false
            }
    
            when (state.searchDisplay) {
                SearchDisplay.InitialResults -> {
    
                }
                SearchDisplay.NoResults -> {
    
                }
    
                SearchDisplay.Suggestions -> {
    
                }
    
                SearchDisplay.Results -> {
     
                }
            }
        }
    }
    

    关于android - Jetpack Compose 状态提升、预览和 ViewModels 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69689843/

    相关文章:

    javascript - Cordova 在输入焦点上禁用收缩 View

    java - 如何将 Android Device Monitor 添加到 Android Studio 的主工具栏?

    android - 如何在flutter中使用firebase登录谷歌时检查用户是新用户还是现有用户?

    android - Ktor:发送响应后删除临时文件

    android - Kotlin使用TikXml解析XML文件

    apache-flex - 为什么 mx :states have trouble being resolved to a component implementation?

    android - 每隔一段时间向android中的videoview播放器添加标记

    android - 使用 Mockito 和 Kotlin 的 Base Presenter Test 类 - 解决通用类型删除

    javascript - 在 React 中显示更多信息

    javascript - 如何防止特定 $state 在另一个 $state 更新时刷新