This is a place I will be testing out React Native.
This example tries to pull together all the navigation schemes
These two files show how it’s done.
/src/components/navigation.js
//@ts-check
import React from 'react'
import {
Button
} from 'react-native'
import {
createStackNavigator
} from '@react-navigation/stack'
import {
createBottomTabNavigator
} from '@react-navigation/bottom-tabs'
import {
createDrawerNavigator
} from '@react-navigation/drawer'
import HomeScreen from '../screens/home-screen'
import DetailScreen from '../screens/detail-screen'
import ProfileScreen from '../screens/profile-screen'
import SettingsScreen from '../screens/settings-screen'
const Stack = createStackNavigator()
const Tab = createBottomTabNavigator()
const Drawer = createDrawerNavigator()
export const MainDrawerNavigator = () => ( <
Drawer.Navigator initialRouteName = 'Home' >
<
Drawer.Screen name = 'Home'
component = {
BottomTabNavigator
}
/> <
Drawer.Screen name = 'Profile'
component = {
ProfileStackNavigator
}
/> < /
Drawer.Navigator >
)
export const BottomTabNavigator = () => ( <
Tab.Navigator >
<
Tab.Screen name = 'Home'
component = {
HomeStackNavigator
}
/> <
Tab.Screen name = 'Settings'
component = {
SettingsStackNavigator
}
/> < /
Tab.Navigator >
)
export const ProfileStackNavigator = () => ( <
Stack.Navigator >
<
Stack.Screen name = 'Profile'
component = {
ProfileScreen
}
/> < /
Stack.Navigator >
)
export const SettingsStackNavigator = () => ( <
Stack.Navigator >
<
Stack.Screen name = 'Setttings'
component = {
SettingsScreen
}
/> < /
Stack.Navigator >
)
export const HomeStackNavigator = () => {
return ( <
Stack.Navigator screenOptions = {
{
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
headerRight: () => ( <
Button onPress = {
() => alert('This is a button!')
}
title = 'Info'
color = '#fff' /
>
),
}
} >
<
Stack.Screen name = 'Home'
component = {
HomeScreen
}
/> <
Stack.Screen name = 'Detail'
component = {
DetailScreen
}
/> < /
Stack.Navigator >
)
}
App.js
//@ts-check
import React from 'react'
import {
SafeAreaProvider
} from 'react-native-safe-area-context'
import {
StyleSheet
} from 'react-native'
import useCachedResources from './src/hooks/useCachedResources'
import {
NavigationContainer
} from '@react-navigation/native'
import {
MainDrawerNavigator
} from './src/components/navigation'
export default function App() {
const isLoadingComplete = useCachedResources()
if (!isLoadingComplete) {
return null
} else {
return ( <
NavigationContainer >
<
MainDrawerNavigator / >
<
/NavigationContainer>
)
}
}
const styles = StyleSheet.create({})
let’s use hooks (useContext and useReducer) to provide global state management. Create a component to do most of the work.
src/context/user-profile-context.js
import React, {
createContext,
useReducer
} from 'react'
const initialState = {
username: 'unknown',
email: '',
authenticated: false,
photoUrl: '/anonymous.jpg',
}
const userProfileContext = createContext(initialState)
const UserProfileProvider = ({
children
}) => {
const [state, dispatch] = useReducer((state, action) => {
switch (action.type) {
case 'login': {
const newState = {
...state,
username: action.payload.username,
authenticated: true,
}
return newState
}
case 'logout':
return {
...initialState
}
default:
throw new Error()
}
}, initialState)
return ( <
userProfileContext.Provider value = {
{
state,
dispatch
}
} > {
children
} <
/userProfileContext.Provider>
)
}
export {
userProfileContext,
UserProfileProvider
}
Now wrap the App with our provider
App.js
//@ts-check
import React from 'react'
...
import {
UserProfileProvider
} from './src/context/user-profile-context'
export default function App() {
const isLoadingComplete = useCachedResources()
if (!isLoadingComplete) {
return null
} else {
return ( <
UserProfileProvider >
<
NavigationContainer >
<
MainDrawerNavigator / >
<
/NavigationContainer> < /
UserProfileProvider >
)
}
}
const styles = StyleSheet.create({})
And finally, use it in the Profile screen by adding two buttons.
src/screens/profile.js
import React, {
useContext
} from 'react'
import {
Button,
Text,
View,
StyleSheet
} from 'react-native'
import {
userProfileContext
} from '../context/user-profile-context'
export default function ProfileScreen({
navigation
}) {
const {
state: userProfile,
dispatch
} = useContext(userProfileContext)
return ( <
View style = {
styles.container
} >
<
Text style = {
styles.title
} > Profile Screen < /Text> {!userProfile.authenticated && ( <
Button title = 'Login'
onPress = {
() =>
dispatch({
type: 'login',
payload: {
username: 'James'
},
})
}
/>
)
} {
userProfile.authenticated && ( <
>
<
Text style = {
styles.title
} > Hello {
userProfile.username
} < /Text> <
Button title = 'Logout'
onPress = {
() => dispatch({
type: 'logout'
})
}
/> < / >
)
} <
/View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
})
Let’s save some data to local storage so we can pull it back when we restart the app. We will put the code in a custom hook.
/src/hooks/use-hooks.js
import {
useState,
useEffect
} from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage'
export default function usePlan() {
const [value, setValue] = useState('')
const [error, setError] = useState(null)
const [isLoading, setIsLoading] = useState(true)
async function getPlan() {
try {
setIsLoading(true)
const value = await AsyncStorage.getItem('@plan')
setValue(value == null ? 'community' : value)
} catch (e) {
setError(e)
} finally {
setIsLoading(false)
}
}
async function setPlan(value) {
try {
const theme = await AsyncStorage.setItem('@plan', value)
setValue(value)
} catch (e) {
setError(e)
}
}
useEffect(() => {
getPlan()
}, [])
return [value, error, isLoading, setPlan]
}
Now lets use the hook in the Settings screen.
src/screens/settings-screen.js
import * as React from 'react'
import {
Text,
View,
StyleSheet
} from 'react-native'
import usePlan from '../hooks/use-plan'
import {
Picker
} from '@react-native-picker/picker'
export default function SettingsScreen({
navigation
}) {
const [plan, planError, planIsLoading, setPlan] = usePlan()
return ( <
View style = {
styles.container
} >
<
Text style = {
styles.title
} > Settings Screen < /Text> <
Text > Your plan is {
planIsLoading ? 'loading' : plan
} < /Text> <
Text style = {
styles.title
} > Choose a plan < /Text> <
Picker selectedValue = {
plan
}
style = {
{
height: 100,
width: 200
}
}
onValueChange = {
(itemValue, itemIndex) => setPlan(itemValue)
} >
<
Picker.Item label = 'Community'
value = 'community' / >
<
Picker.Item label = 'Developer'
value = 'developer' / >
<
Picker.Item label = 'Pro'
value = 'pro' / >
<
/Picker> < /
View >
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
})
Maps in iOS are easier to setup so let’s try that.
yarn add react-native-maps
Create a Map screen
/src/screens/map-screen.js
import * as React from 'react'
import {
View,
StyleSheet,
Dimensions
} from 'react-native'
import MapView, {
Marker
} from 'react-native-maps'
const oxfordPoint = {
latitude: 42.82473,
longitude: -83.26499
}
export default function MapScreen() {
return ( <
View style = {
styles.container
} >
<
MapView mapType = {
Platform.OS == 'android' ? 'none' : 'standard'
}
camera = {
{
center: oxfordPoint,
altitude: 200 * 10000,
pitch: 0,
heading: 0,
zoom: 200,
}
}
style = {
styles.map
}
showsUserLocation = {
true
} >
<
Marker key = {
1
}
coordinate = {
oxfordPoint
}
title = 'Oxford'
description = 'Where I live' /
>
<
/MapView> < /
View >
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
map: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
})
Now add a button to the Home Screen that will take us to the Map Screen
/src/screens/home-screen.js
...
<
Text style = {
styles.title
} > Home Screen < /Text> <
Button title = 'Go to Map'
onPress = {
() => navigation.navigate('Map')
}
/> <
Button
...
Now add our new Map Screen to the HomeStackNavigator stack.
/src/components/navigation.js
...
export const HomeStackNavigator = () => {
return ( <
Stack.Navigator
...option here >
<
Stack.Screen name = 'Home'
component = {
HomeScreen
}
/> <
Stack.Screen name = 'Detail'
component = {
DetailScreen
}
/> <
Stack.Screen name = 'Map'
component = {
MapScreen
}
/> < /
Stack.Navigator >
)
}
...