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

ListView (or perhaps ScrollView) disappears after running in background for several minutes #8607

Closed
nihgwu opened this issue Jul 6, 2016 · 89 comments
Assignees
Labels
Platform: iOS iOS applications. Resolution: Locked This issue was locked by the bot.

Comments

@nihgwu
Copy link
Contributor

nihgwu commented Jul 6, 2016

I'm using the ScrollView as a ViewPager and placing ListView in it just like the F8 app does, and since I upgrade the RN to 0.29 and now 0.30RC0, I'm persecuted by this problem:

navigate to the detail view from the list view ,then press the home button to make the app running in background, and then wait for several minutes to wake up the app, navigate back to the list view, the ListView (or perhaps or outer ScrollView) just disappears until I scroll it vertically or horizontally ( tap has no effect )

I have no idea what happened as it's OK before RN0.29, I've tested on all the 0.29 versions and the newest 0.30RC version they are all the same.

here is the demo:
listview

@nihgwu nihgwu changed the title ListView or perhaps ScrollView disappears after several minutes ListView (or perhaps ScrollView) disappears after running in background for several minutes Jul 6, 2016
@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 7, 2016

I tried to revert the commit 329c716 manually, and now the issue occurs every time, no need for background waiting
listview1

@nicklockwood will you have any time to check it? I'm trying to solve this issue to summit the new version to App Store, thanks

I'll try to revert another commit 1048e5d

nihgwu referenced this issue Jul 7, 2016
Summary:
The `removeClippedSubviews` feature works by umounting views from the hierarchy if they move outside the bounds of their parent.

This was previously restricted to clipping views which had `overflow: hidden`, since we cannot efficiently check whether the subviews of a view go outside its bounds, and so clipping a view that has potentially overflowing children becomes an expensive recursive operation.

The problem with this is that `overflow: visible` is the default, and it's not well documented nor easy to tell that `removeClippedSubviews` has been set up correctly (i.e. with all children having `overflow: hidden`).

When I checked, I found that `removeClippedSubviews` was not working on any of the examples in UIExplorer, nor in several of our internal apps, because the views inside the ListView has `overflow: visible`. This was probably caused by an infra change at some point, but I'm not sure how long it's been broken.

It's vanishingly unlikely that anyone would ever deliberately want subviews to overflow their bounds in this scenario, so I've updated the logic to simply ignore the `overflow` property and assume that views should be clipped if you are using the `removeClippedSubviews` property on the parent.

Cons / Breaking changes: in some rare circumstances, a view might get clipped prematurely if its parent is outside the scrollview bounds, but it itself is inside. This doesn't occur in practice in any of our products, and could be worked around with additional wrapper views if it did.

Pros: removeClippedSubviews is now much easier to use, and much more likely to work as intended, so most list-based apps should see a performance improvement.

Reviewed By: javache

Differential Revision: D3385316

fbshipit-source-id: 1c0064a4c21340a971ba80d794062a356ae6cfb3
@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 7, 2016

still the save after turn off removeClippedSubviews, the ScrollView went to white until scroll

@satya164
Copy link
Contributor

satya164 commented Jul 8, 2016

cc @nicklockwood

@winterbe
Copy link
Contributor

winterbe commented Jul 8, 2016

I'm encountering a similar problem after migrating RN from 0.28 to 0.29. I have a ListView off-screen which gets updated (render is called) due to an action occurring in another view. When navigating back to the ListView all items are invisible until I scroll the View up or down. The items seem to re-appear from the top of the screen.

Edit: Turning off removeClippedSubviews solves the problem for me as mentioned here.

@mroswald
Copy link
Contributor

mroswald commented Jul 8, 2016

We had a similar problem with a ListView on a inactive route which did not render correctly. removeClippedSubviews={false} did the trick. But I didn't find out what was changed between 0.25.1 and 0.29.0 that could relate to this

@mroswald
Copy link
Contributor

mroswald commented Jul 8, 2016

Maybe this one (329c716) or this one (1fcd73f) can be related?

cc @nicklockwood @majak

@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 8, 2016

@mroswald none of the two commits but 1048e5d I've reverted it and the issue is gone

@sjmueller
Copy link
Contributor

We have this same problem too. It usually happens when popping navigation back to an existing listview after the app was in the background. Can confirm that the problem started to occur after 0.28, in 0.29 and still in 0.30.

@majak majak self-assigned this Jul 11, 2016
@majak
Copy link
Contributor

majak commented Jul 11, 2016

Are you able to see this issue on simulator, or does it seem like device only?

@winterbe
Copy link
Contributor

@majak The problem exists both in iOS simulator and on real device. It's reliable reproducible.

@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 11, 2016

BTW, turning off removeClippedSubviews only fixed the issue i've described in my first comment, but doesn't fixed the exact situation:
scrollview(listview) -> navigate to detailview -> goto background for several minutes -> active to detailview -> navigate back to scrollview(listview) -> scrollview goes to blank
there should be something wrong with 1048e5d

@grabbou
Copy link
Contributor

grabbou commented Jul 14, 2016

Same here, after popping route and going to ListView, it stays empty until you interact with it.

@majak
Copy link
Contributor

majak commented Jul 14, 2016

Which navigator are you using?
A simple project with this issue would be invaluable. I wasn't able to repro it so far, so looks like I'm missing something.

@grabbou
Copy link
Contributor

grabbou commented Jul 14, 2016

ExNavigator, not sure if I can set up a reproducible example, but I could try to set up screen share and give you the control so you can place breakpoints here and there ;)

@chirag04
Copy link
Contributor

I can confirm i have seen this as well. Also using ExNavigator.

@grabbou
Copy link
Contributor

grabbou commented Jul 14, 2016

If I won't manage to fix it, I might swizzle that method (in order to revert Nick changes) as I do really need to ship my app soon. But happy to help in anyway possible

@majak
Copy link
Contributor

majak commented Jul 14, 2016

Oh cool, knowing it happens in environment with ExNavigator sounds helpful. Thanks!

@sjmueller
Copy link
Contributor

sjmueller commented Jul 15, 2016

@grabbou that method doesn't even exist in rn 0.30.0.rc.0 or master anymore. @nicklockwood refactored everything shortly after that commit with 46c02b6, so it's even more obscure to manually revert back the offending changes.

Anyone have suggestions on how to fix this in latest?

@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 15, 2016

@grabbou I have to and already revert Nick's commit 1048e5d to release my app, and it works well as before till now, (BTW I'm using 0.30RC0 will this commit reverted)
so is there anyone else in core team will fix this issue ASAP since @nicklockwood has been inactive for a long time

@sjmueller
Copy link
Contributor

Hey @nihgwu can you share your diff on how you reverted 1048e5d on 0.30.0.rc.0? Would be extremely helpful to me and others facing the same problem.

@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 16, 2016

@sjmueller The following is my local version of React/Views/RCTView.m in react-native from L313-L387

- (void)mountOrUnmountSubview:(UIView *)view withClipRect:(CGRect)clipRect relativeToView:(UIView *)clipView
{
  if (view.clipsToBounds) {

    // View has cliping enabled, so we can easily test if it is partially
    // or completely within the clipRect, and mount or unmount it accordingly

    if (!CGRectIsEmpty(CGRectIntersection(clipRect, view.frame))) {

      // View is at least partially visible, so remount it if unmounted
      if (view.superview == nil) {
        [self remountSubview:view];
      }

      // Then test its subviews
      if (CGRectContainsRect(clipRect, view.frame)) {
        [view react_remountAllSubviews];
      } else {
        [view react_updateClippedSubviewsWithClipRect:clipRect relativeToView:clipView];
      }

    } else if (view.superview) {

      // View is completely outside the clipRect, so unmount it
      [view removeFromSuperview];
    }

  } else {

    // View has clipping disabled, so there's no way to tell if it has
    // any visible subviews without an expensive recursive test, so we'll
    // just add it.

    if (view.superview == nil) {
      [self remountSubview:view];
    }

    // Check if subviews need to be mounted/unmounted
    [view react_updateClippedSubviewsWithClipRect:clipRect relativeToView:clipView];
  }
}

- (void)react_updateClippedSubviewsWithClipRect:(CGRect)clipRect relativeToView:(UIView *)clipView
{
  // TODO (#5906496): for scrollviews (the primary use-case) we could
  // optimize this by only doing a range check along the scroll axis,
  // instead of comparing the whole frame

  if (_reactSubviews == nil) {
    // Use default behavior if unmounting is disabled
    return [super react_updateClippedSubviewsWithClipRect:clipRect relativeToView:clipView];
  }

  if (_reactSubviews.count == 0) {
    // Do nothing if we have no subviews
    return;
  }

  if (CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {
    // Do nothing if layout hasn't happened yet
    return;
  }

  // Convert clipping rect to local coordinates
  clipRect = [clipView convertRect:clipRect toView:self];
  clipView = self;
  if (self.clipsToBounds) {
    clipRect = CGRectIntersection(clipRect, self.bounds);
  }

  // Mount / unmount views
  for (UIView *view in _reactSubviews) {
    [self mountOrUnmountSubview:view withClipRect:clipRect relativeToView:clipView];
  }
}

@sjmueller
Copy link
Contributor

Thanks for sharing @nihgwu, however I don't think you are on RN 0.30. As you can see below, the 0.30 lines don't match up with yours:
https://github.com/facebook/react-native/blob/v0.30.0-rc.0/React/Views/RCTView.m#L313-L387

Looks like your local version was before the refactor in 46c02b6!

@nihgwu
Copy link
Contributor Author

nihgwu commented Jul 16, 2016

@sjmueller Sorry I didn't notice there is another commit after 1048e5d, BTW I'm using RN0.30RC0 😊

@nihgwu
Copy link
Contributor Author

nihgwu commented Nov 10, 2016

@majak any news here, I'm waiting to upgrade to the latest RN 😄

nihgwu referenced this issue Nov 11, 2016
Reviewed By: mmmulani

Differential Revision: D4081700

fbshipit-source-id: d4079138dc070565e475831e82651c9b2d5b8d59
@majak
Copy link
Contributor

majak commented Nov 21, 2016

Heads up: we've uncovered the linked solution (625c8cb & co.) doesn't work well with modals, so I've reverted the change on master until we come up with a proper fix 😞

@alloy
Copy link
Contributor

alloy commented Nov 21, 2016

@majak Bummer, was just going to comment that it works well in our app. Good you caught that case, though 👌

@ptomasroos
Copy link
Contributor

ptomasroos commented Nov 21, 2016

Who cares about modal 😔

@nihgwu
Copy link
Contributor Author

nihgwu commented Nov 22, 2016

@majak for most of the time, your commit works really well, but sometimes when I CMD+R to reload the app, the list becomes blank until I scroll it. I think that is a minor issue I can ignore it, but the described issue in this thread has been there for nearly 10 releases since RN0.29, and turning off removeClippedSubviews doesn't work for me, so I'm waiting for a proper workaround for this, even it's not perfect enough but only it works well

? 2016?11?22??01:53?Martin Kralik <notifications@github.commailto:notifications@github.com> ???

Heads up: we've uncovered the linked solution (625c8cbhttps://github.com/facebook/react-native/commit/625c8cb83c7be01b1d5f646b70f8fb1d4c70a45c & co.) doesn't work well with modals, so I've reverted the change on master until we come up with a proper fix ?

You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com//issues/8607#issuecomment-262014664, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ACeY8jW6joUSqeE6_wETe6mS4Kifwct5ks5rAdqegaJpZM4JGSiX.

@ppyupp
Copy link

ppyupp commented Nov 22, 2016

@majak none cares about modal!!!

@narychen
Copy link
Contributor

@nihgwu I'm still using 0.27 since I saw all these messed up things here.
removeClippedSubviews=true will make everything OK on 0.27. If you're in a hurry, you could use the old version as me.

@kkgelu
Copy link

kkgelu commented Nov 25, 2016

removeClippedSubviews={false} causes massive performance issue especially on Android with a list of photos, just be aware if you use that as a solution/workaround.

@dyguests
Copy link

dyguests commented Dec 5, 2016

"react": "15.3.2",
"react-native": "0.37.0",

Same problem happen in ListView with gridLayout({flexDriection:row,flexWrap:wrap}).
it can only show 1st column,but not others column.

before scroll:
image
after scroll:
image

and removeClippedSubviews={false} fixed problem.

@nihgwu
Copy link
Contributor Author

nihgwu commented Dec 7, 2016

@majak FYI, I've upgraded to RN0.40RC0 and seems this issue has gone, I thought you reverted all your commits over clip commits, so I'm wrong?

I've check the commit history, seems you've reverted all the related commits, then why I don't get this issue now

@majak
Copy link
Contributor

majak commented Dec 9, 2016

@nihgwu yes I did revert everything. Could you bisect to figure out why it's working for you now?

@nihgwu
Copy link
Contributor Author

nihgwu commented Dec 9, 2016

@majak Perhaps it's because I'm using Native Animated.event to handle scroll, I'll try to turn off native driver to check.
FYI, I'm sure this issue is gone in my app, I've test for days.

UPDATE: not related to Native Animated.event, I switched to NavigationExperimental from Navigator in this version too, but still not sure if this change makes the issue gone, need more developers to report their status after they upgrade to RN0.40

@jsfroth
Copy link

jsfroth commented Jan 11, 2017

Hi guys,

I just upgraded to RN0.40. The issue is still present in my app. Unlike @nihgwu I'm still using the old Navigator, not NavigationExperimental.

@majak Are there any new estimates for a solution?

Kind regards
Josef

@hramos
Copy link
Contributor

hramos commented Mar 31, 2017

Closing as ListView is deprecated in 0.43. Use FlatList.

@hramos hramos closed this as completed Mar 31, 2017
@MovingGifts
Copy link

MovingGifts commented Apr 15, 2017

I am having the same issue with FlatList in 0.43 with react-navigation.

Anyone else still having the same issue? Still looking for a solution..

UPDATE:
Adding the below to the FlatList solved the blank rendering until scroll to show items problem:

removeClippedSubviews={false}

I don't know if it's the most efficient solution, but it's the only one I found. If there is a better way to go about this from a performance stand point, please let us know @sahrens

To reproduce the issue:

  1. Scene A has a FlatList of 10 items.
  2. On press of first item, go to Scene B.
  3. Scene B also has a FlatList of some items (even just one is fine to test it though).
  4. Go back to Scene A
  5. Repeat step 2, the list will be empty on Scene B
  6. Scroll up/down in that blank empty list location, the items will show up.

@jasan-s
Copy link

jasan-s commented May 4, 2017

I need sticky Headers so I'm stuck using ListView @hramos. additionally, does setting
removeClippedSubviews ={ false} lead to having my entire list rows render at once?

@Ashoat
Copy link
Contributor

Ashoat commented May 4, 2017

React Native 0.44.0 (latest) has sticky header support for both iOS and Android in SectionList.

@sahrens
Copy link
Contributor

sahrens commented May 4, 2017

removeClippedSubviews does not affect JavaScript so react rendering is the same and initial load/render time will be unaffected, but disabling it loses the native optimization to pull offscreen views out of the view hierarchy and scroll performance may suffer as a result.

@Feng999
Copy link
Contributor

Feng999 commented Jun 28, 2017

does this problem fix? i occur this at RN 0.41 with listView and navigator.
@nihgwu Do you figure out why it's working for you ?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Platform: iOS iOS applications. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests