Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screens are not cleared when calling navigator.replaceAll #396

Open
shpasha opened this issue Apr 20, 2024 · 4 comments
Open

Screens are not cleared when calling navigator.replaceAll #396

shpasha opened this issue Apr 20, 2024 · 4 comments

Comments

@shpasha
Copy link
Contributor

shpasha commented Apr 20, 2024

Suppose our rootNavigator is configured with the following disposeBehavior field:

NavigatorDisposeBehavior(
   disposeNestedNavigators = false,
   disposeSteps = true,
)

And it contains the navigation stack: A -> B -> C

Screen B also contains a nested navigator (for example, this could be a TabScreen) with the stack B1 -> B2 -> B3.
In turn, within screens B1, B2, B3, there are some view models.

From screen C, we perform a rootNavigator.replaceAll action to screen D.

Current Behavior:

  • View models on screens B1, B2, B3 are not cleared (because StepDisposableEffect does not perform recursive clearing of screens).

Expected Behavior:

  • View models on screens B1, B2, B3 are cleared.

It seems logical to me if ViewModels were cleared as soon as the screen they were attached to disappeared from the navigation stack.
This is a critical issue for building hierarchical navigation. Are there any plans to fix this?

@shpasha
Copy link
Contributor Author

shpasha commented Apr 20, 2024

My current workaround is:

  • Pass navigator to NavigatorDisposer class, which inherits ScreenDisposable
  • When Screen is disposed NavigatorDisposer also disposes navigator

Sample code:

private class NavigatorDisposer : ScreenDisposable {

    var navigator: Navigator? = null

    override fun onDispose(screen: Screen) {
        navigator?.let { disposeNavigator(it) }
        navigator = null
    }
}

@Composable
private fun Screen.DisposeNavigatorOnScreenDisposeEffect(navigator: Navigator) {
    val screen = this
    LaunchedEffect(navigator) {
        val disposer = ScreenLifecycleStore.get(screen) {
            NavigatorDisposer()
        }
        disposer.navigator = navigator
    }
}

@Composable
public fun Screen.Navigator(
    screen: Screen,
    disposeBehavior: NavigatorDisposeBehavior = NavigatorDisposeBehavior(),
    onBackPressed: OnBackPressed = { true },
    key: String = compositionUniqueId(),
    content: NavigatorContent = { CurrentScreen() }
) {
    Navigator(
        screen = screen,
        disposeBehavior = disposeBehavior,
        onBackPressed = onBackPressed,
        key = key,
        content = { navigator ->
            DisposeNavigatorOnScreenDisposeEffect(navigator)
            content(navigator)
        }
    )
}

But I don't think this is the best way

@hristogochev
Copy link

hristogochev commented Apr 28, 2024

What would the disposeNavigator function be in your workaround? @shpasha

@hristogochev
Copy link

I believe the solution I've come up with for #402 may also help this issue.

@shpasha
Copy link
Contributor Author

shpasha commented May 1, 2024

What would the disposeNavigator function be in your workaround? @shpasha

@hristogochev you can find disposeNavigator function implementation in voyager source codes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants