satya164 / react-native-tab-view

A cross-platform Tab View component for React Native
MIT License
5.13k stars 1.07k forks source link

Not performant on large routes #778

Closed nastarfan closed 5 years ago

nastarfan commented 5 years ago

Current behaviour

Trying to use it to make dynamic tabs based on data provided in a quite big array (120 entries of data), but having performance issues when loading the tab view and switching between tabs.

Expected behaviour

I've read and followed Optimization Tips and expected it to be performant but even loading the tabs takes ages.

Code sample

Here's a code to reproduce the issue

class TemplateScreen extends PureComponent {
  // sample 'template' screen to display the data
  render() {
    const {
      route: { key },
    } = this.props;

    return (
      <View style={styles.container}>
        <Text>I am {key} screen</Text>
      </View>
    );
  }
}

export default class ProduceBug extends Component {
  constructor(props) {
    super(props);
    const data = Array.from({ length: 120 }); // dummy data, routes are populated from it
    const routes = [];

    data.forEach((item, index) => {
      routes.push({
        // create route object and push it to routes
        key: (index + 1).toString(),
        title: (index + 1).toString(),
      });
    });

    this.state = {
      index: 0,
      routes,
    };
  }

  renderScene = ({ route }) => {
    const { index, routes } = this.state;

    if (Math.abs(index - routes.indexOf(route)) > 2) {
      // only renders left and right scene
      return <View />;
    }
    return <TemplateScreen route={route} />;
  };

  renderTabBar = (props) => (
    <TabBar
      {...props}
      scrollEnabled
      indicatorStyle={styles.indicator}
      style={styles.tabbar}
      tabStyle={styles.tab}
      labelStyle={styles.label}
    />
  );

  render() {
    const initialLayout = {
      height: 0,
      width: Dimensions.get('window').width,
    };

    return (
      <TabView
        navigationState={this.state}
        onIndexChange={(index) => this.setState({ index })}
        initialLayout={initialLayout}
        renderScene={this.renderScene}
        renderTabBar={this.renderTabBar}
        lazy
      />
    );
  }
}

What have you tried

It works well with small number of data, like 5, but once it gets bigger it becomes very laggy. I've tried to improve the performance by following provided tips, but can't really achieve tolerable performance

Your Environment

software version
ios or android android
react-native 0.59.5
react-native-tab-view 2.2.0
react-native-gesture-handler 1.2.0
react-native-reanimated 1.0.1
satya164 commented 5 years ago

Please upgrade to the latest version which should have improved performance #720

even loading the tabs takes ages.

In the example, there are 120 tabs being rendered, and even if you're not rendering the screens itself, the tabbar still has to render all of the route labels. If you don't render the tab bar, there's no issue with performance from what I tested.

You can re-implement the tabbar to fit your use case. The default tab bar is not made for such a huge amount of routes.

dhl1402 commented 5 years ago

Please reopen. I have the same issue after upgrade to the latest version. The new default TabBarItem take a very long time to render.

Here's some performance tracking of the same code, rendering 50 routes

Version 2.5.0 (~2600ms)

perf

Version 1.4.1 (~250ms)

perf2

Reproducible sample code

https://snack.expo.io/@dhl1402/react-native-tabview-reproduce-repo

ghost commented 5 years ago

hey @dhl1402 did you find a solution to optimise tabbar time to mount ?