react-navigation-schema
A schema generator extension for react-navigation. Simply pass your NavigationContainer and react-navigation-schema
will provide you with an svg schema and the corresponding JSON file.
Click here to see the JSON for this schema.
Installation
yarn add -D react-navigation-schema
Usage
Start the server
First we need to start our server that generates the files for us. In your terminal, go to the root of the project and run:
yarn react-navigation-schema
This should start our server and give you this initial result:
react-navigation-schema server running at http://127.0.0.1:3000/
You need to have this terminal running if you want your schema to be generated.
Add the generator
Now pass your NavigationContainer
as a JSX.Element
, so the generator can do its magic.
import { createNavigationSchema } from 'react-navigation-schema';
...
useEffect(() => {
createNavigationSchema(Container());
}, []);
...
export function Container() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Group>
<Stack.Screen name="Home" component={SomeScreen} />
<Stack.Screen name="Details" component={SomeScreen} />
</Stack.Group>
<Stack.Screen name="People" component={PeopleStack} />
<Stack.Screen name="Utils" component={SettingsStack} />
<Stack.Screen name="Settings" component={SettingsStack} />
</Stack.Navigator>
</NavigationContainer>
);
}
You can call the createNavigationSchema
anywhere you like as long as you can pass the NavigationContainer
inside it properly. Since this is a dev environment thing, it will only work in the condition of __DEV__ === true
;
Now all you have to do is runn the application as regular on an emulator.
yarn android
Example
The example for the above displayed schema
import React, { useEffect } from 'react';
import type { Node } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import SomeScreen from './screens/SomeScreen';
import PeopleStack from './screens/PeopleStack';
import SettingsStack from './screens/SettingsStack';
import { createNavigationSchema } from 'react-navigation-schema';
const MainStack = createNativeStackNavigator();
const People = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const App: () => Node = () => {
useEffect(() => {
createNavigationSchema(Container());
}, []);
return <Container />;
};
export default App;
export function Container() {
return (
<NavigationContainer>
<MainStack.Navigator>
<MainStack.Group>
<MainStack.Screen name='Home' component={SomeScreen} />
<MainStack.Screen name='Details' component={SomeScreen} />
</MainStack.Group>
<MainStack.Screen name='People' component={PeopleStack} />
<MainStack.Screen name='Utils' component={SettingsStack} />
<MainStack.Screen name='Settings' component={SettingsStack} />
</MainStack.Navigator>
</NavigationContainer>
);
}
function PeopleStack() {
return (
<People.Navigator>
<People.Screen name='Information' component={SomeScreen} />
<People.Screen name='Salary' component={SomeScreen} />
<People.Screen name='Data' component={SettingsStack} />
</People.Navigator>
);
}
function SettingsStack() {
return (
<Tab.Navigator id='Grouped'>
<Tab.Group navigationKey='Grouped'>
<Tab.Screen navigationKey='Grouped' name='View Settings' component={SomeScreen} />
<Tab.Screen navigationKey='Grouped' name='Edit Settings' component={SomeScreen} />
</Tab.Group>
</Tab.Navigator>
);
}
Parameters
You can currently change the port, background color, font size and spacing via the server. Here's a simple example:
yarn react-navigation-schema --port=12345 --color=red --spacing=30 --fontSize=12
One thing to remember here is if you want to set the port, you also have to pass the same port as a parameter inside createNavigationSchema
.
createNavigationSchema(Container(), 12345);
Grouping & Ungrouping
Ungrouping
Sometimes it is necessary to use the same stack twice under one navigation tree. You can decide how you want this to be displayed in the schema. The default behavior for this is ungrouped
.
This is a simple example to show the SettingsStack being used twice.
export function Container() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="People" component={PeopleStack} />
<Stack.Screen name="Utils" component={SettingsStack} />
</Stack.Navigator>
</NavigationContainer>
);
}
function PeopleStack() {
return (
<People.Navigator>
<People.Screen name="Salary" component={SomeScreen} />
<People.Screen name="Data" component={SettingsStack} />
</People.Navigator>
);
}
function SettingsStack() {
return (
<Tab.Navigator>
<Tab.Group>
<Tab.Screen name="View Settings" component={SomeScreen} />
<Tab.Screen name="Edit Settings" component={SomeScreen} />
</Tab.Group>
</Tab.Navigator>
);
}
This example will result in this:
JSON file here for reference.
As you can see, even though 5 - Data
and 10 - Utils
are the exact same, they get split into separate branches. This happens because of the auto-generated identifiers that you see in the beginning of every node. This is necessary because otherwise there can be unwanted match-ups due to names and the schema would be completely broken.
Grouping
So how does grouping work? It's actually very simple, you just need to identify the grouped stacks and screens.
Our ungrouped example would look like this when grouped.
export function NavCon() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="People" component={PeopleStack} />
<Stack.Screen name="Utils" component={SettingsStack} />
</Stack.Navigator>
</NavigationContainer>
);
}
function PeopleStack() {
return (
<People.Navigator>
<People.Screen name="Salary" component={SomeScreen} />
<People.Screen name="Data" component={SettingsStack} />
</People.Navigator>
);
}
function SettingsStack() {
return (
<Tab.Navigator id="Grouped">
<Tab.Group navigationKey="Grouped">
<Tab.Screen
navigationKey="Grouped"
name="View Settings"
component={SomeScreen}
/>
<Tab.Screen
navigationKey="Grouped"
name="Edit Settings"
component={SomeScreen}
/>
</Tab.Group>
</Tab.Navigator>
);
}
Here's the schema result:
JSON file here for reference.
As you can see, now both 5 - Data
and 10 - Utils
go to the same BottomTabNavigator
. This grouping can be achieved with either the id
or the navigationKey
props.