CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-native-tab-view

Cross-platform Tab View component for React Native applications with swipeable, scrollable tab interfaces and smooth animations

Pending
Overview
Eval results
Files

scene-map.mddocs/

Scene Mapping

Scene mapping provides utility functions for efficiently mapping route keys to React components and creating scene renderers. The SceneMap function is the most common way to define tab content in React Native Tab View.

Capabilities

SceneMap Function

Helper function that creates scene renderers from a mapping of route keys to React components.

/**
 * Creates a scene renderer function from a component mapping
 * @param scenes - Object mapping route keys to React components
 * @returns Scene renderer function compatible with TabView.renderScene
 */
function SceneMap<T>(scenes: { [key: string]: React.ComponentType<T> }): 
  (props: SceneRendererProps & { route: Route }) => React.ReactElement;

Usage Examples:

import React from 'react';
import { View, Text } from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view';

// Define individual scene components
const HomeScreen = () => (
  <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
    <Text>Home Screen</Text>
  </View>
);

const ProfileScreen = () => (
  <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
    <Text>Profile Screen</Text>
  </View>
);

const SettingsScreen = () => (
  <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
    <Text>Settings Screen</Text>
  </View>
);

// Create scene renderer using SceneMap
const renderScene = SceneMap({
  home: HomeScreen,
  profile: ProfileScreen,
  settings: SettingsScreen,
});

// Use with TabView
const TabViewExample = () => {
  const [index, setIndex] = useState(0);
  const [routes] = useState([
    { key: 'home', title: 'Home' },
    { key: 'profile', title: 'Profile' },
    { key: 'settings', title: 'Settings' },
  ]);

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

Advanced Scene Rendering

For more complex scenarios, you can create custom scene renderers instead of using SceneMap.

/**
 * Custom scene renderer function type
 * @param props - Scene renderer props including route and navigation context
 * @returns React node to render for the scene
 */
type SceneRenderer<T extends Route> = (
  props: SceneRendererProps & { route: T }
) => React.ReactNode;

/**
 * Scene renderer props interface
 */
interface SceneRendererProps {
  /** Current layout dimensions */
  layout: Layout;
  /** Animated position value for transitions */
  position: Animated.AnimatedInterpolation<number>;
  /** Function to navigate to a specific route */
  jumpTo: (key: string) => void;
}

Custom Scene Renderer Examples:

import React from 'react';
import { TabView, NavigationState, Route } from 'react-native-tab-view';

// Custom scene renderer with conditional logic
const renderScene = ({ route, layout, position, jumpTo }: SceneRendererProps & { route: Route }) => {
  switch (route.key) {
    case 'home':
      return <HomeScreen layout={layout} position={position} jumpTo={jumpTo} />;
    case 'profile':
      return <ProfileScreen userId={getCurrentUserId()} />;
    case 'settings':
      return <SettingsScreen onNavigate={jumpTo} />;
    case 'notifications':
      return (
        <NotificationsScreen
          badgeCount={getNotificationCount()}
          onMarkAllRead={() => markAllNotificationsRead()}
        />
      );
    default:
      return null;
  }
};

// Scene renderer with props passing
const renderSceneWithProps = (sceneProps: SceneRendererProps & { route: Route }) => {
  const commonProps = {
    theme: currentTheme,
    user: currentUser,
    navigation: sceneProps.jumpTo,
  };

  switch (sceneProps.route.key) {
    case 'feed':
      return <FeedScreen {...commonProps} refreshing={isRefreshing} />;
    case 'search':
      return <SearchScreen {...commonProps} query={searchQuery} />;
    case 'profile':
      return <ProfileScreen {...commonProps} userId={sceneProps.route.userId} />;
    default:
      return null;
  }
};

Scene Component Architecture

Understanding how SceneMap creates scene components internally.

/**
 * Internal scene component props
 */
interface SceneProps {
  /** Route object */
  route: any;
  /** Function to navigate to route */
  jumpTo: (key: string) => void;
  /** Animated position value */
  position: Animated.AnimatedInterpolation<number>;
}

/**
 * Internal SceneComponent for rendering individual scenes
 */
declare const SceneComponent: React.MemoExoticComponent<
  <T extends { component: React.ComponentType<any> } & SceneProps>(
    props: T
  ) => React.ReactElement
>;

Performance Considerations

SceneMap uses React.memo for performance optimization and efficient re-rendering.

Performance Best Practices:

// ✅ Good: Components defined outside render
const HomeScreen = React.memo(() => (
  <View><Text>Home</Text></View>
));

const ProfileScreen = React.memo(() => (
  <View><Text>Profile</Text></View>
));

const renderScene = SceneMap({
  home: HomeScreen,
  profile: ProfileScreen,
});

// ❌ Avoid: Inline components (will recreate on every render)
const renderScene = SceneMap({
  home: () => <View><Text>Home</Text></View>,
  profile: () => <View><Text>Profile</Text></View>,
});

// ✅ Better: Memoized inline components if necessary
const renderScene = SceneMap({
  home: React.memo(() => <View><Text>Home</Text></View>),
  profile: React.memo(() => <View><Text>Profile</Text></View>),
});

Dynamic Scene Loading

Handling dynamic route configurations and lazy-loaded scenes.

// Dynamic scene mapping based on user permissions
const createSceneMap = (userRoles: string[]) => {
  const scenes: { [key: string]: React.ComponentType } = {
    home: HomeScreen,
    profile: ProfileScreen,
  };

  if (userRoles.includes('admin')) {
    scenes.admin = AdminScreen;
    scenes.analytics = AnalyticsScreen;
  }

  if (userRoles.includes('moderator')) {
    scenes.moderation = ModerationScreen;
  }

  return SceneMap(scenes);
};

// Lazy loading with dynamic imports
const LazySceneMap = (scenes: { [key: string]: () => Promise<{ default: React.ComponentType }> }) => {
  const [loadedScenes, setLoadedScenes] = useState<{ [key: string]: React.ComponentType }>({});

  const renderScene = ({ route }: { route: Route }) => {
    const SceneComponent = loadedScenes[route.key];
    
    if (SceneComponent) {
      return <SceneComponent />;
    }

    // Load scene dynamically
    const loader = scenes[route.key];
    if (loader) {
      loader().then(module => {
        setLoadedScenes(prev => ({
          ...prev,
          [route.key]: module.default,
        }));
      });
    }

    return <LoadingPlaceholder />;
  };

  return renderScene;
};

// Usage with dynamic imports
const lazyRenderScene = LazySceneMap({
  home: () => import('./screens/HomeScreen'),
  profile: () => import('./screens/ProfileScreen'),
  settings: () => import('./screens/SettingsScreen'),
});

Integration with Navigation Libraries

SceneMap works seamlessly with React Navigation and other navigation libraries.

// Integration with React Navigation
import { useNavigation } from '@react-navigation/native';

const NavigationAwareScreen = () => {
  const navigation = useNavigation();
  
  return (
    <View>
      <Button 
        title="Go to Details" 
        onPress={() => navigation.navigate('Details')} 
      />
    </View>
  );
};

const renderScene = SceneMap({
  tabs: NavigationAwareScreen,
});

// Passing navigation props through scene renderer
const renderSceneWithNavigation = ({ route, jumpTo }: SceneRendererProps & { route: Route }) => {
  const navigationProps = {
    jumpTo,
    canGoBack: () => true,
    goBack: () => jumpTo('home'),
  };

  switch (route.key) {
    case 'home':
      return <HomeScreen navigation={navigationProps} />;
    case 'profile':
      return <ProfileScreen navigation={navigationProps} />;
    default:
      return null;
  }
};

Install with Tessl CLI

npx tessl i tessl/npm-react-native-tab-view

docs

index.md

scene-map.md

tab-bar-indicator.md

tab-bar-item.md

tab-bar.md

tab-view.md

tile.json