I am building a simple app following Mitch Tabian's youtube tutorial about Jetpack Compose. In the State Hoisting video, he extracts the code for the search TextField into a separate Composable. When I do so, my textField doesn't update the value and I can't find what I am doing wrong.
SearchAppBar Composable
@Composable
fun SearchAppBar(
query: String,
onQueryChanged: (String) -> Unit,
onExecuteSearch: () -> Unit,
selectedCategory: FoodCategory?,
onSelectedCategoryChanged: (String) -> Unit
) {
Surface(
modifier = Modifier
.fillMaxWidth(),
color = Color.White,
elevation = 4.dp
) {
Column {
Row(modifier = Modifier.fillMaxWidth()) {
val focusManager = LocalFocusManager.current
OutlinedTextField(
value = query,
onValueChange = { newValue -> onQueryChanged(newValue) },
modifier = Modifier
.background(color = MaterialTheme.colors.surface)
.fillMaxWidth()
.padding(8.dp),
label = {
Text(text = "Search")
},
...
Fragment
class RecipeListFragment : Fragment() {
private val viewModel: RecipeListViewModel by viewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return ComposeView(requireContext()).apply {
setContent {
val recipes = viewModel.recipes.value
val query = viewModel.query.value
val selectedCategory = viewModel.selectedCategory.value
Column {
SearchAppBar(
query = query,
onQueryChanged = { viewModel.onQueryChanged(query) },
onExecuteSearch = { viewModel::newSearch },
selectedCategory = selectedCategory,
onSelectedCategoryChanged = { viewModel::onSelectedCategoryChanged })
LazyColumn {
itemsIndexed(items = recipes) { index, recipe ->
RecipeCard(recipe = recipe, onClick = { })
}
}
}
}
}
}
}
ViewModel
class RecipeListViewModel @Inject constructor(private val repository: RecipeRepository, @Named("auth_token") private val token: String) : ViewModel() {
val recipes: MutableState<List<Recipe>> = mutableStateOf(listOf())
val query = mutableStateOf("")
val selectedCategory: MutableState<FoodCategory?> = mutableStateOf(null)
init {
newSearch()
}
fun onQueryChanged(query: String) {
this.query.value = query
}
fun newSearch() {
viewModelScope.launch {
recipes.value = repository.search(token = token, page = 1, query = query.value)
}
}
fun onSelectedCategoryChanged(category: String) {
val newCategory = getFoodCategory(category)
selectedCategory.value = newCategory
onQueryChanged(category)
}
}