Hey everyone, I have a question: Is it okay to use...
# compose-android
w
Hey everyone, I have a question: Is it okay to use a
data class
as a state holder in Jetpack Compose instead of a
sealed class
or
sealed interface
?
p
It depends, a popular pattern is separating your UI modeling in
View State
and
View Data
You use the sealed class for
View State and data class for View Data
Like bellow:
Copy code
sealed class MyViewState {
  class Initial(viewData: ViewInitialData) : MyViewState ()
  class FetchingRemoteData(viewData: LoadingAnimationData) : ...
  class Content(contentData: ContentData) : ...
  class Error(errorData: ErrorData) : ...
  class RetryingFromError(loadingAnimData: LoadingAnimData)
}
Copy code
data class ViewInitialData ...
data class LoadingAnimationData ...
data class ContentData
data class ErrorData
z
They’re orthogonal. A sealed type is abstract by definition, a data class is concrete. Data classes can extend sealed types.
☝️ 2
☝🏿 1
☝🏾 1
w
Copy code
@Immutable
data class HomeUIState(
    val isLoading: Boolean = false,
    val userRole: String = "",
    val firstName: String = "",
    val lastName: String = "",
    val profileImage: String = "",
    val balance: Double = 0.0,
    val appVersion: String = "",
    val currentLanguage: String = "en".uppercase(),
    val currentTheme: String = THEME_LIGHT,
    val isRefreshing: Boolean = false,
    val filteredTClasses: List<TClassComm> = emptyList(),
    val filteredMaterials: List<MaterialComm> = emptyList(),
    val navigationPathFlow: List<String> = listOf("Top Level")
)

this is my homeUiState class is this approach is fine to avoid/skip unnecessary recomposition?
This is how i am updating state
Copy code
fun onPullToRefreshTrigger() {
    viewModelScope.launch {
        navigationRepo.getAllRelevantNavigationTClasses().collect { tClass ->
            val newState = when (tClass) {
                is DataState.Loading -> _homeUIState.value.copy(isRefreshing = tClass.isLoading)
                is DataState.Data -> {
                    _allTClasses.value = tClass.data
                    _homeUIState.value.copy(
                        filteredTClasses = _allTClasses.value.filter { it.parentTClassId == null },
                        filteredMaterials = emptyList(),
                        navigationPathFlow = listOf("Top Level")
                    )
                }
                is DataState.Messages -> {
                    <http://LocalMessageEvent.post|LocalMessageEvent.post>(BaseLocalMessagesEvent.LocalMessages(tClass.messages))
                    _homeUIState.value
                }
            }
            _homeUIState.value = newState // Single state update
        }
    }
}
this cause my home screen recompose 3 to 4 times i want to just clarifying is this normal ? or in future this can me lead to performance issues.!
Screen Recording 2025-03-28 at 11.56.15 AM.mov
I also noticed that my navigation icon is also recomposing
Copy code
TLoadBaseScreen(isLoading = homeUIState.isLoading, topBar = {
    CenterAlignedTopAppBar(
        title = {
            // title
        },
        navigationIcon = {
            Icon(
                painter = painterResource(R.drawable.baseline_menu_24),
                contentDescription = stringResource(<http://R.string.menu|R.string.menu>), // Accessibility improvement
                modifier = Modifier
                    .padding(start = 12.dp)
                    .size(24.dp) // Ensuring proper touch target
                    .clickable {
                        coroutineScope.launch {
                            if (drawerState.isClosed) {
                                drawerState.open()
                            }
                        }
                    }
            )
        },
        actions = {
           // action 
        },
        modifier = modifier.shadow(
            elevation = 4.dp,
            spotColor = MaterialTheme.colorScheme.primary, // Theme-based color instead of hardcoded Orange
            ambientColor = MaterialTheme.colorScheme.primary
        )
    )

}, content = { paddingValues -> 
//rest of the content of screen 
}
z
“My navigation icon is recomposing” is not a help request
w
I don't understand could you please explain a bit? @Zach Klippenstein (he/him) [MOD]