Repository navigation
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
The focused change isolates saved state with correct lifecycle initialization and no identified blocking issues.
No open issues 🎉
What changed in this PR
Isolates Android pager Compose saved state from the host Fragment, preventing remounted pagers from restoring another pager’s page instead of using initialPage.
Changes:
- Gives each pager’s existing lifecycle owner a private saved-state registry.
- Initializes the registry without restored state and assigns it to the Compose view.
| File | Description |
|---|---|
| android/src/main/java/com/reactnativepagerview/ComposePagerView.kt | Adds and connects a private saved-state registry while preserving lifecycle behavior. |
Review effort: Balanced
ArekChr
left a comment
There was a problem hiding this comment.
@abulenok Thanks for the contribution! The fix makes sense to me.
Before merging, could you add a regression test that saves the old pager position, remounts it with a different initialPage, and checks that the new value is used? Ideally, it should fail before this fix and pass after it.
Could you also add a short changelog note? Apps relying on native state restoration may now return to initialPage after Activity or process recreation.
|
This also fixes a crash we see on Android, so here is a second reason to merge it. Symptom: Cause: the largest entry in the saved Bundle (about 500 KB) was the We fixed it locally by wrapping |
|
@abulenok Could you please address the regression test and changelog note from my review? The additional crash report makes this fix even more useful, but I’d still like to see the test before approving |
…state The pager's internal ComposeView has no view id, so Compose saved its rememberSaveable state (the pager's current page, the page hosts' view state) in the host Fragment's SavedStateRegistry under the shared key "SaveableStateRegistry:-1". When react-native-screens destroys the Fragment view of a covered screen, that state is saved, and a pager mounted afterwards restores it: it starts on the old page and ignores initialPage. Give the ComposeView a SavedStateRegistryOwner from the same private owner that already provides its Lifecycle. Its registry starts empty and is never saved, so nothing is persisted or restored. React owns the pager state, so nothing is lost. A unique view id would also avoid the collision, but every remount would leave an orphaned entry in the Fragment's saved state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0257c61 to
2480976
Compare
|
@ArekChr I added the regression test and a changlelog note in the description. Let me know, if there is a better place for the note. The test fails on main and works correctly with the change from this PR |
Changelog
initialPage. Before, it could start on the page of a previous pager on the same screen, after react-native-screens restored that screen's saved view state.initialPageafter Activity or process recreationSummary
Problem. Since 9.0, each
PagerViewon Android draws through a Jetpack Compose view inside the native view. Compose stores some state withrememberSaveable, including the pager's current page. That state goes into the host Fragment's saved-state store, keyed by the view's id. The pager's internal view has no id, so every pager in the app uses the same key (SaveableStateRegistry:-1).When react-native-screens destroys the view of a screen that's covered by another, it saves that state. The next pager to mount under that key restores the old page and ignores
initialPage. In our app, Home remounts its pager after the user reorder feeds, so it opened on the old index and the tab bar didn't match the feed shown.Solution. The library already gives the Compose view its own private Lifecycle owner so that react-native-screens can't kill it. The fix makes that same object provide the saved-state store too. The store starts empty and is never written out, so nothing is saved or restored. That's fine because React already owns the pager's state (
initialPageand the page events).Test Plan
What's required for testing (prerequisites)?
What are the steps to reproduce (after prerequisites)?
Compatibility
Checklist
README.md