UNPKG

4.14 kBTypeScriptView Raw
1import * as React from 'react';
2import {
3 StyleSheet,
4 View,
5 StyleProp,
6 ViewStyle,
7 LayoutChangeEvent,
8} from 'react-native';
9import TabBar from './TabBar';
10import SceneView from './SceneView';
11import Pager from './Pager';
12import type {
13 Layout,
14 NavigationState,
15 Route,
16 SceneRendererProps,
17 PagerProps,
18} from './types';
19
20export type Props<T extends Route> = PagerProps & {
21 onIndexChange: (index: number) => void;
22 navigationState: NavigationState<T>;
23 renderScene: (props: SceneRendererProps & { route: T }) => React.ReactNode;
24 renderLazyPlaceholder?: (props: { route: T }) => React.ReactNode;
25 renderTabBar?: (
26 props: SceneRendererProps & { navigationState: NavigationState<T> }
27 ) => React.ReactNode;
28 tabBarPosition?: 'top' | 'bottom';
29 initialLayout?: Partial<Layout>;
30 lazy?: ((props: { route: T }) => boolean) | boolean;
31 lazyPreloadDistance?: number;
32 sceneContainerStyle?: StyleProp<ViewStyle>;
33 style?: StyleProp<ViewStyle>;
34};
35
36export default function TabView<T extends Route>({
37 onIndexChange,
38 navigationState,
39 renderScene,
40 initialLayout,
41 keyboardDismissMode = 'auto',
42 lazy = false,
43 lazyPreloadDistance = 0,
44 onSwipeStart,
45 onSwipeEnd,
46 renderLazyPlaceholder = () => null,
47 renderTabBar = (props) => <TabBar {...props} />,
48 sceneContainerStyle,
49 style,
50 swipeEnabled = true,
51 tabBarPosition = 'top',
52}: Props<T>) {
53 const [layout, setLayout] = React.useState({
54 width: 0,
55 height: 0,
56 ...initialLayout,
57 });
58
59 const jumpToIndex = (index: number) => {
60 if (index !== navigationState.index) {
61 onIndexChange(index);
62 }
63 };
64
65 const handleLayout = (e: LayoutChangeEvent) => {
66 const { height, width } = e.nativeEvent.layout;
67
68 setLayout((prevLayout) => {
69 if (prevLayout.width === width && prevLayout.height === height) {
70 return prevLayout;
71 }
72
73 return { height, width };
74 });
75 };
76
77 return (
78 <View onLayout={handleLayout} style={[styles.pager, style]}>
79 <Pager
80 layout={layout}
81 navigationState={navigationState}
82 keyboardDismissMode={keyboardDismissMode}
83 swipeEnabled={swipeEnabled}
84 onSwipeStart={onSwipeStart}
85 onSwipeEnd={onSwipeEnd}
86 onIndexChange={jumpToIndex}
87 >
88 {({ position, render, addEnterListener, jumpTo }) => {
89 // All of the props here must not change between re-renders
90 // This is crucial to optimizing the routes with PureComponent
91 const sceneRendererProps = {
92 position,
93 layout,
94 jumpTo,
95 };
96
97 return (
98 <React.Fragment>
99 {tabBarPosition === 'top' &&
100 renderTabBar({
101 ...sceneRendererProps,
102 navigationState,
103 })}
104 {render(
105 navigationState.routes.map((route, i) => {
106 return (
107 <SceneView
108 {...sceneRendererProps}
109 addEnterListener={addEnterListener}
110 key={route.key}
111 index={i}
112 lazy={typeof lazy === 'function' ? lazy({ route }) : lazy}
113 lazyPreloadDistance={lazyPreloadDistance}
114 navigationState={navigationState}
115 style={sceneContainerStyle}
116 >
117 {({ loading }) =>
118 loading
119 ? renderLazyPlaceholder({ route })
120 : renderScene({
121 ...sceneRendererProps,
122 route,
123 })
124 }
125 </SceneView>
126 );
127 })
128 )}
129 {tabBarPosition === 'bottom' &&
130 renderTabBar({
131 ...sceneRendererProps,
132 navigationState,
133 })}
134 </React.Fragment>
135 );
136 }}
137 </Pager>
138 </View>
139 );
140}
141
142const styles = StyleSheet.create({
143 pager: {
144 flex: 1,
145 overflow: 'hidden',
146 },
147});