How to stop double render in react-native-tab-view using React Hooks

855 views Asked by At

I am using react-native-tab-view for creating swipe tabs, but when I swipe from one tab to another I get my us effect of each component called every time when I swipe it.

My problem is similar as this issue on Github: https://github.com/satya164/react-native-tab-view/issues/750

Current behaviour

When I use 'switch render' scene inside of the hooks function - I get two renders (when we just start app):

 const _renderScene = ({ route }) => {
    switch (route.key) {
      case 'login':
        return <FirstRoute />;
      case 'sign_up':
        return <SecondRoute />;
      default:
        return null;
    }
  };
index.js:17  FirstRoute
index.js:28 SecondRoute
index.js:17 FirstRoute
index.js:28 SecondRoute

When switch between tabs - also received two render - every time!

index.js:17 FirstRoute
index.js:28 SecondRoute

Expected behaviour

When use the same code but with this method:

  const _renderScene = SceneMap({
    login: FirstRoute,
    sign_up: SecondRoute,
  });

Code sample:

import React, { useState } from 'react';
import {
  Text,
  View,
  Keyboard,
} from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import { TabView, TabBar, SceneMap } from 'react-native-tab-view';

import { DEVICE_WIDTH } from 'config/constants';

import styles from './styles';

const FirstRoute = () => {
  console.log('FirstRoute');
  return (
    <View>
      <Text>
        Lorem ipsum dolor sit amet
      </Text>
    </View>
  );
};

const SecondRoute = () => {
  console.log('SecondRoute');
  return (
    <View>
      <Text>
        Lorem ipsum dolor sit amet
      </Text>
    </View>
  );
};

const INITIAL_STATE = {
  index: 0,
  routes: [
    {
      key: 'login',
      title: 'Login',
      icon: '',
      accessibilityLabel: 'Login',
      testID: 'loginTab',
    },
    {
      key: 'sign_up',
      title: 'Register',
      icon: '',
      accessibilityLabel: 'SignIn',
      testID: 'signInTab',
    },
  ],
};

const LoginScreen = () => {
  const [state, setState] = useState(INITIAL_STATE);

  const _renderScene = SceneMap({
    login: FirstRoute,
    sign_up: SecondRoute,
  });

  // const _renderScene = ({ route }) => {
  //   switch (route.key) {
  //     case 'login':
  //       return <FirstRoute />;
  //     case 'sign_up':
  //       return <SecondRoute stings={[]} />;
  //     default:
  //       return null;
  //   }
  // };

  const _handleIndexChange = (index) => {
    Keyboard.dismiss();
    setState({ ...INITIAL_STATE, index });
  };

  const _renderTabBar = props => (
    <TabBar
      {...props}
      activeColor={EStyleSheet.value('$primaryColor')}
      inactiveColor="black"
      style={styles.tabBar}
      indicatorStyle={styles.indicatorStyle}
    />
  );

  return (
    <View style={styles.container}>
      <TabView
        // lazy
        navigationState={state}
        renderScene={_renderScene}
        renderTabBar={_renderTabBar}
        onIndexChange={_handleIndexChange}
        // swipeEnabled={false}
        initialLayout={{
          height: 0,
          width: DEVICE_WIDTH,
        }}
      />
    </View>
  );
};

export default LoginScreen;

I tried below a few solutions, but all in vain. Pease help.
Used useCallBack:

const _renderScene = useCallback(SceneMap({ login: FirstRoute, sign_up: SecondRoute }));

Also used useMemo but got the error bellow:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

const firstRoute = useMemo(() => (), []);

or

const LoginUser = React.memo(() => ());

Please help.

Expected behaviour

When use the same code but with this method

const _renderScene = SceneMap({ login: FirstRoute, sign_up: SecondRoute, }); All as expected (when we just start app) index.js:17 FirstRoute index.js:28 SecondRoute

0

There are 0 answers