因此,在 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()
,您可以手动实例化一个)并在 Preview
中使用此可组合(预览不支持创建这样的 View 模型)所以我看到的“最干净”的解决方案是仅在最高可组合级别实例化我的 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/