react-native-tab-view icon indicating copy to clipboard operation
react-native-tab-view copied to clipboard

Lazy load doesn't works correctly

Open batuhansahan opened this issue 5 years ago • 15 comments

Current behaviour

Example: Tab1 - Tab2 - Tab3

Active tab: tab1 Target tab: tab3

When i want to go to "tab 3" by click it is rendering tab2 on the way.

Expected behaviour

Not render tab2 or what ever is between 2 tabs when sliding.

Code sample

in main file

  const renderScene = ({ route }) => {
    switch (route.key) {
      case 'tab1':
        return <Tab1 someProps />;
      case 'tab2':
        return <Tab2 someProps />;
      case 'tab3':
        return <Tab3 someProps />;
      default:
        return null;
    }
  };

also

In the tab2 i have useEffect thats how i know the tab2 renders when the screens moving

  useEffect(() => {
    apiSearch(query)
  }, []);

Your Environment

software version
ios or android android
react-native 0.61.5
react-native-tab-view 2.13.0
react-native-gesture-handler 1.6.0
react-native-reanimated 1.7.1
node 10.x
npm or yarn yarn,npm

batuhansahan avatar Mar 27 '20 19:03 batuhansahan

same issue

ThanhNguyen140797 avatar May 25 '20 06:05 ThanhNguyen140797

same issue @osdnk can you please verify this issue ? thank you

haxiha avatar May 28 '20 08:05 haxiha

Hi, I solved this issue using renderPager prop like:


import {
  TabView,
  ScrollPager,
} from 'react-native-tab-view';

<TabView
        lazy
        style={{ marginTop: getStatusBarHeight() }}
        navigationState={{ index, routes: routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={initialLayout}
        renderTabBar={renderTabBar}
        renderLazyPlaceholder={() => <Placeholder />}
        renderPager={
          IS_ANDROID ? undefined : (props) => <ScrollPager {...props} />
        }
      />

renatobentorocha avatar Jun 17 '20 17:06 renatobentorocha

Hi, I solved this issue using renderPager prop like:

import {
  TabView,
  ScrollPager,
} from 'react-native-tab-view';

<TabView
        lazy
        style={{ marginTop: getStatusBarHeight() }}
        navigationState={{ index, routes: routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={initialLayout}
        renderTabBar={renderTabBar}
        renderLazyPlaceholder={() => <Placeholder />}
        renderPager={
          IS_ANDROID ? undefined : (props) => <ScrollPager {...props} />
        }
      />

Only work on ios

ThanhNguyen140797 avatar Jun 18 '20 13:06 ThanhNguyen140797

Hi, I solved this issue using renderPager prop like:

import {
  TabView,
  ScrollPager,
} from 'react-native-tab-view';

<TabView
        lazy
        style={{ marginTop: getStatusBarHeight() }}
        navigationState={{ index, routes: routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={initialLayout}
        renderTabBar={renderTabBar}
        renderLazyPlaceholder={() => <Placeholder />}
        renderPager={
          IS_ANDROID ? undefined : (props) => <ScrollPager {...props} />
        }
      />

Only work on ios

In my tests it worked on both. Below, my packages versions:

"name": "react-native-tab-view", "version": "2.14.4",

"name": "react-native", "version": "0.62.2",

renatobentorocha avatar Jun 18 '20 13:06 renatobentorocha

Hi, I solved this issue using renderPager prop like:

import {
  TabView,
  ScrollPager,
} from 'react-native-tab-view';

<TabView
        lazy
        style={{ marginTop: getStatusBarHeight() }}
        navigationState={{ index, routes: routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={initialLayout}
        renderTabBar={renderTabBar}
        renderLazyPlaceholder={() => <Placeholder />}
        renderPager={
          IS_ANDROID ? undefined : (props) => <ScrollPager {...props} />
        }
      />

Only work on ios

In my tests it worked on both. Below, my packages versions:

"name": "react-native-tab-view", "version": "2.14.4",

"name": "react-native", "version": "0.62.2",

It work perfect, but my screen using FlatList and i can't swipe to refresh (RefreshControl) when using rengerPager ScrollPager in iOS

ThanhNguyen140797 avatar Jun 19 '20 01:06 ThanhNguyen140797

Hi, I solved this issue using renderPager prop like:

import {
  TabView,
  ScrollPager,
} from 'react-native-tab-view';

<TabView
        lazy
        style={{ marginTop: getStatusBarHeight() }}
        navigationState={{ index, routes: routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={initialLayout}
        renderTabBar={renderTabBar}
        renderLazyPlaceholder={() => <Placeholder />}
        renderPager={
          IS_ANDROID ? undefined : (props) => <ScrollPager {...props} />
        }
      />

Only work on ios

In my tests it worked on both. Below, my packages versions: "name": "react-native-tab-view", "version": "2.14.4", "name": "react-native", "version": "0.62.2",

It work perfect, but my screen using FlatList and i can't swipe to refresh (RefreshControl) when using rengerPager ScrollPager in iOS

The same here, but you can use an infinity scroll to load more items. It worked here.

renatobentorocha avatar Jun 19 '20 16:06 renatobentorocha

Any updates here? Same issue.

PedroBern avatar Aug 13 '20 22:08 PedroBern

Quick Fix using with React Navigation

I'm using the following hook. If it returns false, I render a placeholder instead of my screen.

import { useIsFocused } from '@react-navigation/native'
import React from 'react'

/**
 * Return `true` if should be mounted. If returning `false`, you should render a placehold.
 */
export const useLazyTabScreen = (): boolean => {
  const [shouldMount, setShouldMount] = React.useState(false)
  const isFocused = useIsFocused()

  React.useEffect(() => {
    if (isFocused) {
      setShouldMount(true)
    }
  }, [isFocused])

  return shouldMount
}

PedroBern avatar Aug 14 '20 12:08 PedroBern

i am also facing the same issue. is there any update or any solution for this?

i tried above solutions but doesn't work for me.

Prinkal151 avatar Nov 06 '20 09:11 Prinkal151

Hi, I'm still facing the same issue. Any solutions please? thank you

anhquan291 avatar Jul 27 '21 08:07 anhquan291

@anhquan291 I found a fix/ workaround. The issue is caused by the Pager implementation.

in the Pager code for version 2.16.0 I removed lines 595 - 613 inclusive and that solved it for me.

I paste the code I deleted below in case that helps.

onChange(
      this.position,
      // Listen to updates in the position to detect when we enter a screen
      // This is useful for things such as lazy loading when index change will fire too late
      cond(
        I18nManager.isRTL
          ? lessThan(this.gestureX, 0)
          : greaterThan(this.gestureX, 0),
        // Based on the direction of the gesture, determine if we're entering the previous or next screen
        cond(neq(floor(this.position), this.lastEnteredIndex), [
          set(this.lastEnteredIndex, floor(this.position)),
          call([floor(this.position)], this.handleEnteredIndexChange),
        ]),
        cond(neq(ceil(this.position), this.lastEnteredIndex), [
          set(this.lastEnteredIndex, ceil(this.position)),
          call([ceil(this.position)], this.handleEnteredIndexChange),
        ])
      )
    ),

seanowenhayes avatar Jul 29 '21 08:07 seanowenhayes

@anhquan291 I found a fix/ workaround. The issue is caused by the Pager implementation.

in the Pager code for version 2.16.0 I removed lines 595 - 613 inclusive and that solved it for me.

I paste the code I deleted below in case that helps.

onChange(
      this.position,
      // Listen to updates in the position to detect when we enter a screen
      // This is useful for things such as lazy loading when index change will fire too late
      cond(
        I18nManager.isRTL
          ? lessThan(this.gestureX, 0)
          : greaterThan(this.gestureX, 0),
        // Based on the direction of the gesture, determine if we're entering the previous or next screen
        cond(neq(floor(this.position), this.lastEnteredIndex), [
          set(this.lastEnteredIndex, floor(this.position)),
          call([floor(this.position)], this.handleEnteredIndexChange),
        ]),
        cond(neq(ceil(this.position), this.lastEnteredIndex), [
          set(this.lastEnteredIndex, ceil(this.position)),
          call([ceil(this.position)], this.handleEnteredIndexChange),
        ])
      )
    ),

Thank you @seanowenhayes. I'm gonna try it now.

anhquan291 avatar Jul 29 '21 08:07 anhquan291

Lazy load does not work correctly on android and ios. In web it will display the lazy placeholder when loading the scene. On android it loaded all scenes in one go.

renzified avatar Dec 30 '21 03:12 renzified

Same problem here. Did anyone find a solution?

jfaq89 avatar Aug 19 '22 14:08 jfaq89

Hey, this was solved here #1392 and released in 3.3.0

okwasniewski avatar Oct 11 '22 18:10 okwasniewski