Okay creating ViewModel at Top Level in Component and then passing it down to the lower Composable Components is One of the solution u can use it for your project but one of the best solution i encounter at my project is using "ViewModelStoreOwner"
here is the one by one step and other solution u can use in you project according to your need
Be Aware in this i use Koin for DI insted of Dagger Hilt
Problem Summary
Currently, I am facing an issue in handling ViewModel across two different Composables.
Scenario
I use the same ViewModel in two different Composables: Composable A and Composable B.
I create the ViewModel instance using: val viewModel: MyViewModel = koinViewModel()
Issue Observed
When I navigate from Composable A to Composable B using:
navController.navigate("${NavigationConfig.SWITCH_TEAMS_SCREEN}/${data_one }/${data_two}/${data_three}")
the ViewModel in Composable B acts as a new instance, resulting in: Loss of all data created or retrieved in Composable A.
Root Cause
Koin creates a new ViewModel instance per destination because by default: Each navigation destination recomposes independently and requests its own ViewModel and The ViewModel is scoped to the current navigation back stack entry.
Impact
Data loss between composables using the same ViewModel.
Redundant API calls or data recreation, leading to performance issues and inconsistent user experience.
Solution one : Share the data which is required to the composable B through Navigation
Solution Two : share the create the ViewModel at top level and share it to the lower components .
Solution Three: By default:
A ViewModel's scope is tied to either:
The Composable lifecycle (recreated on recomposition or navigation), or
The Activity/Fragment lifecycle if created in them.
What changes with viewModelStoreOwner? When you use:
val parentEntry = remember { navController.getBackStackEntry(NavigationConfig.MATCH_GRAPH) }
val viewModel: MatchScreenViewModel = koinViewModel(viewModelStoreOwner = parentEntry)
and use this view model in that composable .
Also remember , to access this same view model object in another screen evern after navController.navigate(). you need to use val parentEntry = remember { navController.getBackStackEntry(NavigationConfig.MATCH_GRAPH) }
val viewModel: MatchScreenViewModel = koinViewModel(viewModelStoreOwner = parentEntry)
for creating view model object in new compose. : it will work fine in all those screen which come under the defined NavGraph .
You are specifying that:
The NavGraph itself acts as the ViewModelStoreOwner.
The ViewModel instance is now scoped to the MATCH_GRAPH NavGraph route.
✅ Why is this beneficial?
Shared instance across multiple destinations within the NavGraph.
Both Composable A and Composable B will use the same ViewModel instance.
Data fetched or modified in one composable will be instantly available in the other.
Lifecycle-safe.
The ViewModel will remain alive as long as the MATCH_GRAPH NavGraph is in the back stack.
Once the NavGraph is popped from the back stack, the ViewModel is automatically destroyed, ensuring no memory leaks.
Optimized architecture.
Avoids redundant data fetching.
Prevents unnecessary ViewModel recreations, improving performance and user experience.
🔍 How it works internally?
navController.getBackStackEntry(NavigationConfig.MATCH_GRAPH) retrieves the NavBackStackEntry for MATCH_GRAPH.
Passing it as viewModelStoreOwner tells Koin:
“Use this NavGraph’s lifecycle to manage the ViewModel instance.
Compose will now reuse the same ViewModel across all composables under that NavGraph, unless the NavGraph is popped.
Solution Four : use scope ViewModel but it is applicable for Activity or fragments
(according to https://insert-koin.io/docs/reference/koin-android/viewmodel)