Skip to content

Commit a3c1f65

Browse files
authored
Merge pull request #5 from okwasniewski/feat/new-api
feat: introduce new API
2 parents 5d59edf + 36a7d53 commit a3c1f65

File tree

12 files changed

+268
-181
lines changed

12 files changed

+268
-181
lines changed

README.md

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,33 @@ yarn add react-native-bottom-tabs
2121

2222

2323
```tsx
24-
import { TabView } from "react-native-bottom-tabs";
25-
26-
const items: TabViewItems = [
27-
{ key: 'article', title: 'Article', icon: 'document.fill' },
28-
{ key: 'albums', title: 'Albums', icon: 'square.grid.2x2.fill', badge: '3' },
29-
{ key: 'contacts', title: 'Contacts', icon: 'person.fill' },
30-
];
31-
32-
export default function App() {
33-
const [selectedPage, setSelectedTab] = useState<string>('contacts');
24+
import TabView, { SceneMap } from 'react-native-bottom-tabs';
25+
26+
export default function ThreeTabs() {
27+
const [index, setIndex] = useState(0);
28+
const [routes] = useState([
29+
{ key: 'article', title: 'Article', icon: 'document.fill', badge: '!' },
30+
{
31+
key: 'albums',
32+
title: 'Albums',
33+
icon: 'square.grid.2x2.fill',
34+
badge: '5',
35+
},
36+
{ key: 'contacts', title: 'Contacts', icon: 'person.fill' },
37+
]);
38+
39+
const renderScene = SceneMap({
40+
article: Article,
41+
albums: Albums,
42+
contacts: Contacts,
43+
});
3444

3545
return (
3646
<TabView
37-
style={styles.fullWidth}
38-
items={items}
39-
selectedPage={selectedPage}
40-
onPageSelected={handlePageSelected}
41-
>
42-
<View/>
43-
<View/>
44-
<View/>
45-
</TabView>
47+
navigationState={{ index, routes }}
48+
onIndexChange={setIndex}
49+
renderScene={renderScene}
50+
/>
4651
);
4752
}
4853
```

example/src/Examples/FourTabs.tsx

Lines changed: 25 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,36 @@
1-
import { StyleSheet } from 'react-native';
2-
import TabView, {
3-
type OnPageSelectedEventData,
4-
type TabViewItems,
5-
} from 'react-native-bottom-tabs';
1+
import TabView, { SceneMap } from 'react-native-bottom-tabs';
62
import { useState } from 'react';
73
import { Article } from '../Screens/Article';
84
import { Albums } from '../Screens/Albums';
9-
import { Chat } from '../Screens/Chat';
105
import { Contacts } from '../Screens/Contacts';
6+
import { Chat } from '../Screens/Chat';
117

12-
const items: TabViewItems = [
13-
{ key: 'article', title: 'Article', icon: 'document.fill', badge: '!' },
14-
{ key: 'albums', title: 'Albums', icon: 'square.grid.2x2.fill', badge: '5' },
15-
{ key: 'contacts', title: 'Contacts', icon: 'person.fill' },
16-
{ key: 'chat', title: 'Chat', icon: 'keyboard' },
17-
];
18-
19-
export default function FourTabs() {
20-
const [selectedPage, setSelectedTab] = useState<string>('contacts');
21-
22-
const handlePageSelected = ({
23-
nativeEvent: { key },
24-
}: {
25-
nativeEvent: OnPageSelectedEventData;
26-
}) => setSelectedTab(key);
8+
export default function ThreeTabs() {
9+
const [index, setIndex] = useState(0);
10+
const [routes] = useState([
11+
{ key: 'article', title: 'Article', icon: 'document.fill', badge: '!' },
12+
{
13+
key: 'albums',
14+
title: 'Albums',
15+
icon: 'square.grid.2x2.fill',
16+
badge: '5',
17+
},
18+
{ key: 'contacts', title: 'Contacts', icon: 'person.fill' },
19+
{ key: 'chat', title: 'Chat', icon: 'keyboard' },
20+
]);
2721

28-
const goToAlbums = () => {
29-
setSelectedTab('albums');
30-
};
22+
const renderScene = SceneMap({
23+
article: Article,
24+
albums: Albums,
25+
contacts: Contacts,
26+
chat: Chat,
27+
});
3128

3229
return (
3330
<TabView
34-
style={styles.fullWidth}
35-
items={items}
36-
tabViewStyle="sidebarAdaptable"
37-
selectedPage={selectedPage}
38-
onPageSelected={handlePageSelected}
39-
>
40-
<Article onClick={goToAlbums} />
41-
<Albums />
42-
<Contacts />
43-
<Chat />
44-
</TabView>
31+
navigationState={{ index, routes }}
32+
onIndexChange={setIndex}
33+
renderScene={renderScene}
34+
/>
4535
);
4636
}
47-
48-
const styles = StyleSheet.create({
49-
fullWidth: {
50-
width: '100%',
51-
height: '100%',
52-
},
53-
});

example/src/Examples/ThreeTabs.tsx

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,33 @@
1-
import { StyleSheet } from 'react-native';
2-
import TabView, {
3-
type OnPageSelectedEventData,
4-
type TabViewItems,
5-
} from 'react-native-bottom-tabs';
1+
import TabView, { SceneMap } from 'react-native-bottom-tabs';
62
import { useState } from 'react';
73
import { Article } from '../Screens/Article';
84
import { Albums } from '../Screens/Albums';
95
import { Contacts } from '../Screens/Contacts';
106

11-
const items: TabViewItems = [
12-
{ key: 'article', title: 'Article', icon: 'document.fill', badge: '!' },
13-
{ key: 'albums', title: 'Albums', icon: 'square.grid.2x2.fill', badge: '5' },
14-
{ key: 'contacts', title: 'Contacts', icon: 'person.fill' },
15-
];
16-
177
export default function ThreeTabs() {
18-
const [selectedPage, setSelectedTab] = useState<string>('contacts');
19-
20-
const handlePageSelected = ({
21-
nativeEvent: { key },
22-
}: {
23-
nativeEvent: OnPageSelectedEventData;
24-
}) => setSelectedTab(key);
8+
const [index, setIndex] = useState(0);
9+
const [routes] = useState([
10+
{ key: 'article', title: 'Article', icon: 'document.fill', badge: '!' },
11+
{
12+
key: 'albums',
13+
title: 'Albums',
14+
icon: 'square.grid.2x2.fill',
15+
badge: '5',
16+
},
17+
{ key: 'contacts', title: 'Contacts', icon: 'person.fill' },
18+
]);
2519

26-
const goToAlbums = () => {
27-
setSelectedTab('albums');
28-
};
20+
const renderScene = SceneMap({
21+
article: Article,
22+
albums: Albums,
23+
contacts: Contacts,
24+
});
2925

3026
return (
3127
<TabView
32-
style={styles.fullWidth}
33-
items={items}
34-
tabViewStyle="sidebarAdaptable"
35-
selectedPage={selectedPage}
36-
onPageSelected={handlePageSelected}
37-
>
38-
<Article onClick={goToAlbums} />
39-
<Albums />
40-
<Contacts />
41-
</TabView>
28+
navigationState={{ index, routes }}
29+
onIndexChange={setIndex}
30+
renderScene={renderScene}
31+
/>
4232
);
4333
}
44-
45-
const styles = StyleSheet.create({
46-
fullWidth: {
47-
width: '100%',
48-
height: '100%',
49-
},
50-
});

example/src/Screens/Article.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313

1414
type Props = Partial<ScrollViewProps> & {
1515
date?: string;
16-
onClick?: () => void;
16+
jumpTo?: (key: string) => void;
1717
author?: {
1818
name: string;
1919
};
@@ -42,7 +42,7 @@ const DEFAULT_AUTHOR = {
4242
export function Article({
4343
date = '1st Jan 2025',
4444
author = DEFAULT_AUTHOR,
45-
onClick,
45+
jumpTo,
4646
...rest
4747
}: Props) {
4848
const ref = React.useRef<ScrollView>(null);
@@ -65,7 +65,12 @@ export function Article({
6565
<Text style={[styles.timestamp, { color: '#000' }]}>{date}</Text>
6666
</View>
6767
</View>
68-
<Button title="Go to Albums" onPress={onClick} />
68+
<Button
69+
title="Go to Albums"
70+
onPress={() => {
71+
jumpTo?.('albums');
72+
}}
73+
/>
6974
<Heading>What is Lorem Ipsum?</Heading>
7075
<Paragraph>
7176
Lorem Ipsum is simply dummy text of the printing and typesetting

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,5 +195,8 @@
195195
"create-react-native-library": {
196196
"type": "view-mixed",
197197
"version": "0.41.2"
198+
},
199+
"dependencies": {
200+
"use-latest-callback": "^0.2.1"
198201
}
199202
}

src/SceneMap.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as React from 'react';
2+
3+
type SceneProps = {
4+
route: any;
5+
jumpTo: (key: string) => void;
6+
};
7+
8+
const SceneComponent = React.memo(
9+
<T extends { component: React.ComponentType<any> } & SceneProps>({
10+
component,
11+
...rest
12+
}: T) => {
13+
return React.createElement(component, rest);
14+
}
15+
);
16+
17+
SceneComponent.displayName = 'SceneComponent';
18+
19+
export function SceneMap<T>(scenes: { [key: string]: React.ComponentType<T> }) {
20+
return ({ route, jumpTo }: SceneProps) => {
21+
const component = scenes[route.key];
22+
if (!component) {
23+
return null;
24+
}
25+
return (
26+
<SceneComponent
27+
key={route.key}
28+
jumpTo={jumpTo}
29+
component={component}
30+
route={route}
31+
/>
32+
);
33+
};
34+
}

src/TabView.android.tsx

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)