Repository navigation
FlatList: Pull to Refresh refresh controls are "freezed" after navigation.goBack() #41515
Description
Activity
- addedNeeds: ReproThis issue could be improved with a clear list of steps to reproduce the issue.This issue could be improved with a clear list of steps to reproduce the issue.
on Nov 16, 2023 ⚠️ Missing Reproducible Example ℹ️ We could not detect a reproducible example in your issue report. Please provide either: - If your bug is UI related: a Snack
- If your bug is build/update related: use our Reproducer Template. A reproducer needs to be in a GitHub repository under your username.
+1 same isuues. when switch tab or back to desktop and return app.
screen loss of focus happens。
only iOS0.73.0-rc.4
Is this a regression from 0.72?
0.73.0-rc.4
Is this a regression from 0.72?
0.72.4
My observations, it is happening only when I write logs, so they are showing in metro. In release build with logs turned off everything is working as expected.
Maybe communication with metro in async operation is breaking something.
@ivanignatiev can you try on 0.72 and confirm if the issue persists there or not?
@cortinico i have same issue on 0.72.1
Demo Repository: https://github.com/huiqun922/rn_nav.git
2023-11-30.14.24.28.mov
- addedIssue: Author Provided ReproThis issue can be reproduced in Snack or an attached project.This issue can be reproduced in Snack or an attached project.
on Nov 30, 2023 same issue with 0.72.12
+1
Still issue on 0.81
Reacted by Miguel ManoI've been fighting this bug for years, and I just let Claude have a crack at it. The future is scary and impressive. Here's my fix for this now, for any who dare attempt it...
There are actually two separate bugs with similar symptoms, both caused by the refresh control being detached from the window while its screen is inactive. With react-native-screens, inactive bottom tabs and covered native-stack screens are detached.
Environment
- Expo SDK 54, React Native 0.81.5, old architecture (
newArchEnabled: false). Can't move to the new architecture yet because of problems with Reanimated scroll handlers. - react-native-screens ~4.16, @react-navigation/bottom-tabs 7 and native-stack 7
- FlashList 1.7.6 wrapped with
Animated.createAnimatedComponent, plus plain FlatLists. It isn't list-specific. - Built from source (not prebuilt RN core), tested on iOS 18.7.8
Bug 1: refresh ends while detached, spinner stuck forever
Repro: pull to refresh, then switch tabs or
goBack()before the fetch finishes. JS setsrefreshing={false}while the screen is inactive. When you return, the spinner is frozen, the content stays pushed down, and scrolling doesn't clear it.Cause:
endRefreshingProgrammaticallyreturns early when!_hasMovedToWindow, butsetRefreshing:has already set_currentRefreshingState = NO. Nothing replays the skippedendRefreshingwhen the control re-enters a window. JS state and UIKit state stay out of sync permanently.Bug 2: idle control drawn as "pulled" after re-attach
Repro: open a screen whose list is still on its initial load, navigate away during the load, and return after it finishes.
refreshingwas never true, but a frozen spinner is visible. Unlike bug 1, scrolling clears it.Cause: logging showed
super.refreshing == NOand_currentRefreshingState == NOthe whole time, and novalueChangedfired. UIKit was never refreshing. The scroll view's content inset changed during the initial load (from -50 to 48.3 in our case), and after the detach and re-attach, UIKit lays out the idle control as partially pulled. This looks like the issue #31024 fixed by callingendRefreshingindidMoveToWindow. That call isn't in the currentdidMoveToWindow, which only toggles_hasMovedToWindow.Fix (patch-package)
node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.mReconcile the two states one tick after the control re-attaches to a window:
- (void)didMoveToWindow { [super didMoveToWindow]; if (self.window) { _hasMovedToWindow = YES; UInt64 timestamp = _currentRefreshingStateTimestamp; dispatch_async(dispatch_get_main_queue(), ^{ if (!self.window || timestamp != self->_currentRefreshingStateTimestamp) { return; // detached again, or setRefreshing: already ran while attached } [self _reconcileRefreshingAfterReattach]; }); } else { _hasMovedToWindow = NO; } } - (void)_reconcileRefreshingAfterReattach { if (_currentRefreshingState) { return; } if (!super.refreshing) { // Bug 2: reset idle layout (what #31024 did), and re-trigger the // control's offset observation the same way a manual scroll does. [super endRefreshing]; UIScrollView *scrollView = self.scrollView; if (scrollView) { [scrollView setContentOffset:scrollView.contentOffset animated:NO]; } return; } // Bug 1: replay the endRefreshing that was skipped while detached. UIScrollView *scrollView = self.scrollView; if (scrollView && scrollView.contentOffset.y < -scrollView.contentInset.top) { UInt64 ts = _currentRefreshingStateTimestamp; CGPoint offset = {scrollView.contentOffset.x, -scrollView.contentInset.top}; [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ [scrollView setContentOffset:offset]; } completion:^(__unused BOOL finished) { if (ts == self->_currentRefreshingStateTimestamp) { [super endRefreshing]; } }]; } else { [super endRefreshing]; } }
- Expo SDK 54, React Native 0.81.5, old architecture (
Description
I cannot find any open issue for this topic.
I have 2 screens inside same context, useEffect depend on both screens depend on the same state from common context.
When I update context state data on Screen 2, and
goBack()to Screen 1, refresh controls for flatlist are just freezed and I need to pull it to make it disappear:State with
refreshingvalue if changing to false correctly.React Native Version
0.73.0-rc.4
Output of
npx react-native infoSystem:
OS: macOS 14.1.1
CPU: (12) arm64 Apple M3 Pro
Memory: 68.31 MB / 18.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 21.1.0
path: /opt/homebrew/bin/node
Yarn:
version: 1.22.19
path: /opt/homebrew/bin/yarn
npm:
version: 10.2.0
path: /opt/homebrew/bin/npm
Watchman:
version: 2023.11.06.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.14.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 23.0
- iOS 17.0
- macOS 14.0
- tvOS 17.0
- watchOS 10.0
Android SDK: Not Found
IDEs:
Android Studio: 2022.3 AI-223.8836.35.2231.11005911
Xcode:
version: 15.0.1/15A507
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.9
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.73.0-rc.4
wanted: 0.73.0-rc.4
react-native-macos: Not Found
npmGlobalPackages:
"react-native": Not Found
Android:
hermesEnabled: true
newArchEnabled: false
iOS:
hermesEnabled: true
newArchEnabled: false
Steps to reproduce
navigation.goBack()refreshingis falseSnack, screenshot, or link to a repository