Skip to content

Rendering of all data when navigating with @react-navigation/stack #2231

@sharabai

Description

@sharabai

Description

Using @react-navigation/stack, pushing on top of a screen with FlashList makes FlashList render all of the data.

Current behavior

FlashList.stack.bug.mp4

Expected behavior

No additional renders should happen.

Reproduction

Expo Snack or minimal reproduction link:

https://snack.expo.dev/@sharabai/flashlist-renderitem-bug-with-react-stack-navigation?platform=web

Platform

  • iOS
  • Android
  • Web (if applicable)

Environment

FlashList version: 2.3.0

Additional context

The issue is tightly linked to #1816. In the thread under that issue you can find a workaround that involves manually setting some prop in Navigator.

The core problem is that React Navigation on web makes FlashList's dimensions 0x0 when the screen is being pushed on, which makes FlashList recalculate the height of its children and because of it all sorts of problems arise.

Proposed fix that was used at https://github.com/Expensify/App as a patch is doing an early return when FlashList's size is 0x0.
It makes it a lot easier to use in real-life production app without worrying about passing some props to navigation, which can influence perf negatively and you have to remember to do it each time. Working on such a huge projects, it's a lot easier to solve it at the level of FlashList itself.

diff --git a/src/recyclerview/RecyclerView.tsx b/src/recyclerview/RecyclerView.tsx
index 34722d48..c14346f1 100644
--- a/src/recyclerview/RecyclerView.tsx
+++ b/src/recyclerview/RecyclerView.tsx
@@ -166,6 +166,10 @@ const RecyclerViewComponent = <T,>(
     if (internalViewRef.current && firstChildViewRef.current) {
       // Measure the outer container size and inner container layout
       const outerViewSize = measureParentSize(internalViewRef.current);
+      if (outerViewSize.width === 0 && outerViewSize.height === 0) {
+        containerViewSizeRef.current = outerViewSize;
+        return;
+      }
       const firstChildViewLayout = measureFirstChildLayout(
         firstChildViewRef.current,
         internalViewRef.current
@@ -204,6 +208,12 @@ const RecyclerViewComponent = <T,>(
     if (pendingChildIds.size > 0) {
       return;
     }
+    if (
+      containerViewSizeRef.current?.width === 0 &&
+      containerViewSizeRef.current?.height === 0
+    ) {
+      return;
+    }
     const layoutInfo = Array.from(refHolder, ([index, viewHolderRef]) => {
       const layout = measureItemLayout(
         viewHolderRef.current!,

Checklist

  • I've searched existing issues and couldn't find a duplicate
  • I've provided a minimal reproduction (Expo Snack preferred)
  • I'm using the latest version of @shopify/flash-list
  • I've included all required information above

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions