A cross-platform Tab View component for React Native

React Native Tab View A cross-platform Tab View component for React Native.

Features

  • Smooth animations and gestures
  • Scrollable tabs
  • Supports both top and bottom tab bars
  • Follows Material Design spec
  • Highly customizable
  • Fully typed with TypeScript

Demo

Installation

Open a Terminal in the project root and run:

yarn add react-native-tab-view

Now we need to install react-native-gesture-handler and react-native-reanimated.

If you are using Expo, to ensure that you get the compatible versions of the libraries, run:

expo install react-native-gesture-handler react-native-reanimated

If you are not using Expo, run the following:

yarn add react-native-reanimated react-native-gesture-handler

If you are using Expo, you are done. Otherwise, continue to the next steps.

Next, we need to link these libraries. The steps depends on your React Native version:

  • React Native 0.60 and higher
  • On newer versions of React Native, linking is automatic.
  • To complete the linking on iOS, make sure you have Cocoapods installed. Then run:
cd ios
pod install
cd ..
  • React Native 0.59 and lower
  • If you’re on an older React Native version, you need to manually link the dependencies. To do that, run:
react-native link react-native-reanimated
react-native link react-native-gesture-handler

IMPORTANT: There are additional steps required for react-native-gesture-handler on Android after linking (for all React Native versions). Check the this guide to complete the installation.

We’re done! Now you can build and run the app on your device/simulator.

Quick Start

import * as React from 'react';
import { View, StyleSheet, Dimensions } from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view';

const FirstRoute = () => (
  <View style={[styles.scene, { backgroundColor: '#ff4081' }]} />
);

const SecondRoute = () => (
  <View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);

const initialLayout = { width: Dimensions.get('window').width };

export default function TabViewExample() {
  const [index, setIndex] = React.useState(0);
  const [routes] = React.useState([
    { key: 'first', title: 'First' },
    { key: 'second', title: 'Second' },
  ]);

  const renderScene = SceneMap({
    first: FirstRoute,
    second: SecondRoute,
  });

  return (
    <TabView
      navigationState={{ index, routes }}
      renderScene={renderScene}
      onIndexChange={setIndex}
      initialLayout={initialLayout}
    />
  );
}

const styles = StyleSheet.create({
  scene: {
    flex: 1,
  },
});

Try this example on Snack

More examples on Snack

API reference

The package exports a TabView component which is the one you’d use to render the tab view, and a TabBar component which is the default tab bar implementation.

TabView

Container component responsible for rendering and managing tabs. Follows material design styles by default.

Basic usage look like this:

<TabView
  navigationState={{ index, routes }}
  onIndexChange={setIndex}
  renderScene={SceneMap({
    first: FirstRoute,
    second: SecondRoute,
  })}
/>

Props

navigationState (required)

State for the tab view. The state should contain the following properties:

  • index: a number representing the index of the active route in the routes array
  • routes: an array containing a list of route objects used for rendering the tabs

Each route object should contain the following properties:

  • key: a unique key to identify the route (required)
  • title: title for the route to display in the tab bar
  • icon: icon for the route to display in the tab bar
  • accessibilityLabel: accessibility label for the tab button
  • testID: test id for the tab button

Example:

{
  index: 1,
  routes: [
    { key: 'music', title: 'Music' },
    { key: 'albums', title: 'Albums' },
    { key: 'recents', title: 'Recents' },
    { key: 'purchased', title: 'Purchased' },
  ]
}

TabView is a controlled component, which means the index needs to be updated via the onIndexChange callback.

onIndexChange (required)

Callback which is called on tab change, receives the index of the new tab as argument. The navigation state needs to be updated when it’s called, otherwise the change is dropped.

renderScene (required)

Callback which returns a react element to render as the page for the tab. Receives an object containing the route as the argument:

const renderScene = ({ route, jumpTo }) => {
  switch (route.key) {
    case 'music':
      return <MusicRoute jumpTo={jumpTo} />;
    case 'albums':
      return <AlbumsRoute jumpTo={jumpTo} />;
  }
};

You need to make sure that your individual routes implement a shouldComponentUpdate to improve the performance. To make it easier to specify the components, you can use the SceneMap helper.

SceneMap takes an object with the mapping of route.key to React components and returns a function to use with renderScene prop.

import { SceneMap } from 'react-native-tab-view';

...

const renderScene = SceneMap({
  music: MusicRoute,
  albums: AlbumsRoute,
});

Specifying the components this way is easier and takes care of implementing a shouldComponentUpdate method.

Each scene receives the following props:

  • route: the current route rendered by the component
  • jumpTo: method to jump to other tabs, takes a route.key as it’s argument
  • position: animated node which represents the current position

The jumpTo method can be used to navigate to other tabs programmatically:

this.props.jumpTo('albums');

All the scenes rendered with SceneMap are optimized using React.PureComponent and don’t re-render when parent’s props or states change. If you need more control over how your scenes update (e.g. - triggering a re-render even if the navigationState didn’t change), use renderScene directly instead of using SceneMap.

IMPORTANT: Do not pass inline functions to SceneMap, for example, don’t do the following:

SceneMap({
  first: () => <FirstRoute foo={this.props.foo} />,
  second: SecondRoute,
});

Always define your components elsewhere in the top level of the file. If you pass inline functions, it’ll re-create the component every render, which will cause the entire route to unmount and remount every change. It’s very bad for performance and will also cause any local state to be lost.

If you need to pass additional props, use a custom renderScene function:

const renderScene = ({ route }) => {
  switch (route.key) {
    case 'first':
      return <FirstRoute foo={this.props.foo} />;
    case 'second':
      return <SecondRoute />;
    default:
      return null;
  }
};
renderTabBar

Callback which returns a custom React Element to use as the tab bar:

import { TabBar } from 'react-native-tab-view';

...

<TabView
  renderTabBar={props => <TabBar {...props} />}
  ...
/>

If this is not specified, the default tab bar is rendered. You pass this props to customize the default tab bar, provide your own tab bar, or disable the tab bar completely.

<TabView
  renderTabBar={() => null}
  ...
/>
renderPager

Callback which returns a custom React Element to use as pager.

E.g. you can import ScrollPager from react-native-tab-view. It might deliver slightly better experience on iOS.

import { TabView, ScrollPager } from 'react-native-tab-view';
// ...
<TabView
  renderPager={props => <ScrollPager { ...props }/>}
  // ...
/>

Also, you can use ViewPager-based pager with React Native Tab View ViewPager Adapter .

import { TabView } from 'react-native-tab-view';
import ViewPagerAdapter from 'react-native-tab-view-viewpager-adapter';
// ...
<TabView
  renderPager={props => (
    <ViewPagerAdapter {...props} transition="curl" showPageIndicator />
  )}
  // ...
/>
tabBarPosition

Position of the tab bar in the tab view. Possible values are 'top' and 'bottom'. Defaults to 'top'.

lazy

Boolean indicating whether to lazily render the scenes. By default all scenes are rendered to provide a smoother swipe experience. But you might want to defer the rendering of unfocused scenes until the user sees them. To enable lazy rendering, set lazy to true.

When you enable lazy, the unfocused screens will usually take some time to render when they come into focus. You can use the renderLazyPlaceholder prop to customize what the user sees during this short period.

lazyPreloadDistance

When lazy is enabled, you can specify how many adjacent routes should be preloaded with this prop. This value defaults to 0 which means lazy pages are loaded as they come into the viewport.

renderLazyPlaceholder

Callback which returns a custom React Element to render for routes that haven’t been rendered yet. Receives an object containing the route as the argument. The lazy prop also needs to be enabled.

This view is usually only shown for a split second. Keep it lightweight.

By default, this renders null.

removeClippedSubviews

Boolean indicating whether to remove invisible views (such as unfocused screens) from the native view hierarchy to improve memory usage. Defaults to false.

Note: Don’t enable this on iOS where this is buggy and views don’t re-appear.

keyboardDismissMode

String indicating whether the keyboard gets dismissed in response to a drag gesture. Possible values are:

  • 'auto' (default): the keyboard is dismissed when the index changes.
  • 'on-drag': the keyboard is dismissed when a drag begins.
  • 'none': drags do not dismiss the keyboard.
swipeEnabled

Boolean indicating whether to enable swipe gestures. Swipe gestures are enabled by default. Passing false will disable swipe gestures, but the user can still switch tabs by pressing the tab bar.

swipeVelocityImpact

Determines how relevant is a velocity while calculating next position while swiping. Defaults to 0.2.

onSwipeStart

Callback which is called when the swipe gesture starts, i.e. the user touches the screen and moves it.

onSwipeEnd

Callback which is called when the swipe gesture ends, i.e. the user lifts their finger from the screen after the swipe gesture.

timingConfig

Configuration object for the timing animation which occurs when tapping on tabs. Supported properties are:

  • duration (number)
springConfig

Configuration object for the spring animation which occurs after swiping. Supported properties are:

  • damping (number)
  • mass (number)
  • stiffness (number)
  • restSpeedThreshold (number)
  • restDisplacementThreshold (number)
springVelocityScale

Number for determining how meaningful is gesture velocity for calculating initial velocity of spring animation. Defaults to 0.

initialLayout

Object containing the initial height and width of the screens. Passing this will improve the initial rendering performance. For most apps, this is a good default:

<TabView
  initialLayout={{ width: Dimensions.get('window').width }}
  ...
/>
position

Animated value to listen to the position updates. The passed position value will be kept in sync with the current position of the tabs. It’s useful for accessing the animated value outside the tab view.

const [position] = useState(() => new Animated.Value(0));

return (
  <TabView
    position={position}
    ...
  />
);
sceneContainerStyle

Style to apply to the view wrapping each screen. You can pass this to override some default styles such as overflow clipping:

style

Style to apply to the tab view container.

gestureHandlerProps

An object with props to be passed to underlying PanGestureHandler. For example:

<TabView
  gestureHandlerProps={{
    maxPointers: 1,
    waitFor: [someRef]
  }}
  ...
/>

TabBar

Material design themed tab bar. To customize the tab bar, you’d need to use the renderTabBar prop of TabView to render the TabBar and pass additional props.

For example, to customize the indicator color and the tab bar background color, you can pass indicatorStyle and style props to the TabBar respectively:

const renderTabBar = props => (
  <TabBar
    {...props}
    indicatorStyle={{ backgroundColor: 'white' }}
    style={{ backgroundColor: 'pink' }}
  />
);

//...

return (
  <TabView
    renderTabBar={renderTabBar}
    ...
  />
);

Props

getLabelText

Function which takes an object with the current route and returns the label text for the tab. Uses route.title by default.

<TabBar
  getLabelText={({ route }) => route.title}
  ...
/>
getAccessible

Function which takes an object with the current route and returns a boolean to indicate whether to mark a tab as accessible. Defaults to true.

getAccessibilityLabel

Function which takes an object with the current route and returns a accessibility label for the tab button. Uses route.accessibilityLabel by default if specified, otherwise uses the route title.

<TabBar
  getAccessibilityLabel={({ route }) => route.accessibilityLabel}
  ...
/>
getTestID

Function which takes an object with the current route and returns a test id for the tab button to locate this tab button in tests. Uses route.testID by default.

<TabBar
  getTestID={({ route }) => route.testID}
  ...
/>
renderIcon

Function which takes an object with the current route, focused status and color and returns a custom React Element to be used as a icon.

<TabBar
  renderIcon={({ route, focused, color }) => (
    <Icon
      name={focused ? 'abums' : 'albums-outlined'}
      color={color}
    />
  )}
  ...
/>
renderLabel

Function which takes an object with the current route, focused status and color and returns a custom React Element to be used as a label.

<TabBar
  renderLabel={({ route, focused, color }) => (
    <Text style={{ color, margin: 8 }}>
      {route.title}
    </Text>
  )}
  ...
/>
renderTabBarItem

Function which takes a TabBarItemProps object and returns a custom React Element to be used as a tab button.

renderIndicator

Function which takes an object with the current route and returns a custom React Element to be used as a tab indicator.

renderBadge

Function which takes an object with the current route and returns a custom React Element to be used as a badge.

onTabPress

Function to execute on tab press. It receives the scene for the pressed tab, useful for things like scroll to top.

By default, tab press also switches the tab. To prevent this behavior, you can call preventDefault:

<TabBar
  onTabPress={({ route, preventDefault }) => {
    if (route.key === 'home') {
      preventDefault();

      // Do something else
    }
  }}
  ...
/>
onTabLongPress

Function to execute on tab long press, use for things like showing a menu with more options

activeColor

Custom color for icon and label in the active tab.

inactiveColor

Custom color for icon and label in the inactive tab.

pressColor

Color for material ripple (Android >= 5.0 only).

pressOpacity

Opacity for pressed tab (iOS and Android < 5.0 only).

scrollEnabled

Boolean indicating whether to enable scrollable tabs.

If you set scrollEnabled to true, you should also specify a width in tabStyle to improve the initial render.

bounces

Boolean indicating whether the tab bar bounces when scrolling.

tabStyle

Style to apply to the individual tab items in the tab bar.

By default, all tab items take up the same pre-calculated width based on the width of the container. If you want them to take their original width, you can specify width: 'auto' in tabStyle.

indicatorStyle

Style to apply to the active indicator.

indicatorContainerStyle

Style to apply to the container view for the indicator.

labelStyle

Style to apply to the tab item label.

contentContainerStyle

Style to apply to the inner container for tabs.

style

Style to apply to the tab bar container.

ScrollPager

Custom pager which can we used inside renderPager prop. It is based on ScrollView and might bring a slightly better experience on iOS.

Props

It accepts the same set of props as default pager extended with one addition:

ovescroll

When true, the scroll view bounces when it reaches the end of the content. The default value is false.

Using with other libraries

React Navigation

If you want to integrate the tab view with React Navigation’s navigation system, e.g. want to be able to navigate to a tab using navigation.navigate etc, you can use the following official integrations:

Note that some functionalities are not available with the React Navigation 4 integration because of the limitations in React Navigation. For example, it’s possible to dynamically change the rendered tabs.

React Native Navigation (Wix)

If you use React Native Navigation by Wix on Android, you need to wrap all your screens that uses react-native-tab-view with gestureHandlerRootHOC from react-native-gesture-handler. Refer react-native-gesture-handler 's docs for more details.

Mobx

Normally we recommend to use React’s local state to manage the navigation state for the tabs. But if you need to use Mobx to manage the navigation state, there is a gotcha you need to be aware of.

Mobx relies on data being accessed in render to work properly. However, we don’t use the index value inside render in the library, so Mobx fails to track any changes to the index. You might see that the tabs don’t change on pressing on the tab bar if you have a state like this:

@observable navigationState = {
  index: 0,
  routes: [
    { key: 'music', title: 'Music' },
    { key: 'albums', title: 'Albums' },
  ],
};

To workaround this, we need to make sure that index is accessed in render. We can refactor our state to something like this for it to work:

@observer
class MyComponent extends React.Component {
  @observable index = 0;

  @observable routes = [
    { key: 'music', title: 'Music' },
    { key: 'albums', title: 'Albums' },
  ];

  @action handleIndexChange = index => {
    this.index = index;
  };

  render() {
    return (
      <TabView
        navigationState={{ index: this.index, routes: this.routes }}
        renderScene={({ route }) => {
          /* ... */
        }}
        onIndexChange={this.handleIndexChange}
      />
    );
  }
}

Optimization Tips

Avoid unnecessary re-renders

The renderScene function is called every time the index changes. If your renderScene function is expensive, it’s good idea move each route to a separate component if they don’t depend on the index, and use shouldComponentUpdate or React.memo in your route components to prevent unnecessary re-renders.

For example, instead of:

const renderScene = ({ route }) => {
  switch (route.key) {
    case 'home':
      return (
        <View style={styles.page}>
          <Avatar />
          <NewsFeed />
        </View>
      );
    default:
      return null;
  }
};

Do the following:

const renderScene = ({ route }) => {
  switch (route.key) {
    case 'home':
      return <HomeComponent />;
    default:
      return null;
  }
};

Where <HomeComponent /> is a PureComponent if you’re using class components:

export default class HomeComponent extends React.PureComponent {
  render() {
    return (
      <View style={styles.page}>
        <Avatar />
        <NewsFeed />
      </View>
    );
  }
}

Or, wrapped in React.memo if you’re using function components:

function HomeComponent() {
  return (
    <View style={styles.page}>
      <Avatar />
      <NewsFeed />
    </View>
  );
}

export default React.memo(HomeComponent);

Avoid one frame delay

We need to measure the width of the container and hence need to wait before rendering some elements on the screen. If you know the initial width upfront, you can pass it in and we won’t need to wait for measuring it. Most of the time, it’s just the window width.

For example, pass the following initialLayout to TabView:

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

The tab view will still react to changes in the dimension and adjust accordingly to accommodate things like orientation change.

Optimize large number of routes

If you’ve a large number of routes, especially images, it can slow the animation down a lot. You can instead render a limited number of routes.

For example, do the following to render only 2 routes on each side:

const renderScene = ({ route }) => {
  if (Math.abs(index - routes.indexOf(route)) > 2) {
    return <View />;
  }

  return <MySceneComponent route={route} />;
};

Avoid rendering TabView inside ScrollView

Nesting the TabView inside a vertical ScrollView will disable the optimizations in the FlatList components rendered inside the TabView. So avoid doing it if possible.

Use lazy and renderLazyPlaceholder props to render routes as needed

The lazy option is disabled by default to provide a smoother tab switching experience, but you can enable it and provide a placeholder component for a better lazy loading experience. Enabling lazy can improve initial load performance by rendering routes only when they come into view. Refer the prop reference for more details.

Use removeClippedSubviews to improve memory usage

On Android, enabling removeClippedSubviews can improve memory usage. This option can also affect rendering performance negatively, so it is disabled by default. So make sure to test it when enabling it. Refer the prop reference for more details.

Contributing

While developing, you can run the example app to test your changes.

Make sure your code passes TypeScript and ESLint. Run the following to verify:

yarn typescript
yarn lint

To fix formatting errors, run the following:

yarn lint -- --fix

Remember to add tests for your change if possible.

Download Details:

Author: satya164

Demo: https://expo.io/@satya164/react-native-tab-view-demos

Source Code: https://github.com/satya164/react-native-tab-view

#react-native #react #mobile-apps

What is GEEK

Buddha Community

A cross-platform Tab View component for React Native
Autumn  Blick

Autumn Blick

1598839687

How native is React Native? | React Native vs Native App Development

If you are undertaking a mobile app development for your start-up or enterprise, you are likely wondering whether to use React Native. As a popular development framework, React Native helps you to develop near-native mobile apps. However, you are probably also wondering how close you can get to a native app by using React Native. How native is React Native?

In the article, we discuss the similarities between native mobile development and development using React Native. We also touch upon where they differ and how to bridge the gaps. Read on.

A brief introduction to React Native

Let’s briefly set the context first. We will briefly touch upon what React Native is and how it differs from earlier hybrid frameworks.

React Native is a popular JavaScript framework that Facebook has created. You can use this open-source framework to code natively rendering Android and iOS mobile apps. You can use it to develop web apps too.

Facebook has developed React Native based on React, its JavaScript library. The first release of React Native came in March 2015. At the time of writing this article, the latest stable release of React Native is 0.62.0, and it was released in March 2020.

Although relatively new, React Native has acquired a high degree of popularity. The “Stack Overflow Developer Survey 2019” report identifies it as the 8th most loved framework. Facebook, Walmart, and Bloomberg are some of the top companies that use React Native.

The popularity of React Native comes from its advantages. Some of its advantages are as follows:

  • Performance: It delivers optimal performance.
  • Cross-platform development: You can develop both Android and iOS apps with it. The reuse of code expedites development and reduces costs.
  • UI design: React Native enables you to design simple and responsive UI for your mobile app.
  • 3rd party plugins: This framework supports 3rd party plugins.
  • Developer community: A vibrant community of developers support React Native.

Why React Native is fundamentally different from earlier hybrid frameworks

Are you wondering whether React Native is just another of those hybrid frameworks like Ionic or Cordova? It’s not! React Native is fundamentally different from these earlier hybrid frameworks.

React Native is very close to native. Consider the following aspects as described on the React Native website:

  • Access to many native platforms features: The primitives of React Native render to native platform UI. This means that your React Native app will use many native platform APIs as native apps would do.
  • Near-native user experience: React Native provides several native components, and these are platform agnostic.
  • The ease of accessing native APIs: React Native uses a declarative UI paradigm. This enables React Native to interact easily with native platform APIs since React Native wraps existing native code.

Due to these factors, React Native offers many more advantages compared to those earlier hybrid frameworks. We now review them.

#android app #frontend #ios app #mobile app development #benefits of react native #is react native good for mobile app development #native vs #pros and cons of react native #react mobile development #react native development #react native experience #react native framework #react native ios vs android #react native pros and cons #react native vs android #react native vs native #react native vs native performance #react vs native #why react native #why use react native

Juned Ghanchi

1621573085

React Native App Developers India, React Native App Development Company

Expand your user base by using react-native apps developed by our expert team for various platforms like Android, Android TV, iOS, macOS, tvOS, the Web, Windows, and UWP.

We help businesses to scale up the process and achieve greater performance by providing the best react native app development services. Our skilled and experienced team’s apps have delivered all the expected results for our clients across the world.

To achieve growth for your business, hire react native app developers in India. You can count on us for all the technical services and support.

#react native app development company india #react native app developers india #hire react native developers india #react native app development company #react native app developers #hire react native developers

Hire Dedicated React Native Developer

Have you ever thought of having your own app that runs smoothly over multiple platforms?

React Native is an open-source cross-platform mobile application framework which is a great option to create mobile apps for both Android and iOS. Hire Dedicated React Native Developer from top React Native development company, HourlyDeveloper.io to design a spectacular React Native application for your business.

Consult with experts:- https://bit.ly/2A8L4vz

#hire dedicated react native developer #react native development company #react native development services #react native development #react native developer #react native

Platform App Design | Cross-Platform Development Services

Cross-Platform Development Services

With the development in mobile app technology, a huge time saver as well as the quality maintainer technology is Cross-Platform App development. The development of an app that takes less time to develop as well as uses one technology to develop an app for both android and iOS is game-changing technology in mobile app development.

Want to develop or design a Cross-platform app?

With the successful delivery of more than 950 projects, WebClues Infotech has got the expertise as well as a huge experience of cross-platform app development and design. With global offices in 4 continents and a customer presence in most developed countries, WebClues Infotech has got a huge network around the world.

Want to know more about our cross-platform app designs?

Visit: https://www.webcluesinfotech.com/cross-platform-design/

Share your requirements https://www.webcluesinfotech.com/contact-us/

View Portfolio https://www.webcluesinfotech.com/portfolio/

#cross-platform development services #cross platform mobile app development services #cross-platform mobile app development services #cross platform app development services #hire cross platform app developer #hire cross-platform app developer india usa,

Hire Dedicated React Native Developers - WebClues Infotech

Being one of the emerging frameworks for app development the need to develop react native apps has increased over the years.

Looking for a react native developer?

Worry not! WebClues infotech offers services to Hire React Native Developers for your app development needs. We at WebClues Infotech offer a wide range of Web & Mobile App Development services based o your business or Startup requirement for Android and iOS apps.

WebClues Infotech also has a flexible method of cost calculation for hiring react native developers such as Hourly, Weekly, or Project Basis.

Want to get your app idea into reality with a react native framework?

Get in touch with us.

Hire React Native Developer Now: https://www.webcluesinfotech.com/hire-react-native-app-developer/

For inquiry: https://www.webcluesinfotech.com/contact-us/

Email: sales@webcluesinfotech.com

#hire react native developers #hire dedicated react native developers #hire react native developer #hiring a react native developer #hire freelance react native developers #hire react native developers in 1 hour