Navigation Bar
- Published on
The Importance of React Navigation for Developers
As a developer, it is important to stay on top of the latest technologies and tools to ensure that your projects are efficient and effective. One such tool that has gained immense popularity in recent years is React Navigation, which is used to create efficient and aesthetically pleasing navigation systems in React Native applications. In this blog post, we will discuss why developers need to use React Navigation and explore some of its key features and benefits.
1. Simplifies Navigation Setup:
- One of the main reasons why developers need to use React Navigation is that it simplifies navigation setup. With React Navigation, developers can easily create a navigation system with minimal configuration and setup. This means that developers can focus more on building other important features of their application without worrying about complicated navigation setups.
2. Better User Experience:
- Another important benefit of using React Navigation is that it enables developers to create better user experiences. React Navigation provides various customizable options to create visually appealing navigation systems that seamlessly integrate with the overall interface of the application. This enhances the user experience and ensures that the navigation system is both intuitive and easy to use.
3. Cross-Platform Compatibility:
- React Navigation is also useful because it allows for cross-platform compatibility. This means that the navigation system created with React Navigation can be used in both iOS and Android applications, which simplifies the development process. Developers do not need to create two different navigation systems for each platform, which saves a considerable amount of time and effort.
4. Supports Different Navigation Types:
- React Navigation also supports different types of navigation, including stack, tab, and drawer navigation. This allows developers to create the most suitable navigation system depending on the specific needs of their application. This flexibility ensures that the navigation system is both efficient and tailored to the specific requirements of the application.
5. Robust Documentation and Community Support:
- Lastly, React Navigation has robust documentation that serves as a valuable resource for developers who want to learn more about how to use this tool. In addition, there is a supportive community of developers who are willing to offer guidance and support to those who are just starting to use React Navigation. This means that developers do not have to navigate the learning process alone and can leverage the expertise of others in the community.
React Navigation
1. Using React Navigation
2. Focusing on Tab Navigation
- Possibly the most common style of navigation in mobile apps is tab-based navigation. This can be tabs on the bottom of the screen or on the top below the header (or even instead of a header).
- tab navigation
3. Minimal example of tab-based navigation
import * as React from 'react' import { Text, View } from 'react-native' import { NavigationContainer } from '@react-navigation/native' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' function HomeScreen() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Home!</Text> </View> ) } function SettingsScreen() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Settings!</Text> </View> ) } const Tab = createBottomTabNavigator() export default function App() { return ( <NavigationContainer> <Tab.Navigator> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> </NavigationContainer> ) }
4. Customizing the appearance
- Customizing the appearance
- Do Installation
yarn add @expo/vector-icons
- Using Expo vector icons
- Select what icon you want
- Screen Options attribute that can be used in
<Tab.Navigator>
component
Mock Server
- Data transmission: CLOUD --> services.js --> context.js --> application
- Services Layer: Service itself stems to determine what methods we want in order to get data from external (external services provider e.g: Google)
Promise
const myPromise = new Promise((resolve, reject) => { resolve('success') })
myPromise.then((res) => console.log('my promise', res))
const myFetch = fetcth('external url') // transfer JSON to JS object .then((response) => response.json()) // print JS object .then((json) => console.log(json))
Camelize
- yarn add camelize
Spread Operator
In JavaScript, the spread operator... It is mainly used to expand the contents of an array or object into another array or object. However, it can only handle one layer of depth, that is to say, it will not recurs to nested arrays or objects. This means that for nested structures, the extension operator can only "expand" the outer structure.
let nestedObject = { a: 1, b: { c: 2, d: { e: 3, }, }, } let shallowCopy = { ...nestedObject } shallowCopy.b === nestedObject.b // true shallowCopy.b.d === nestedObject.b.d // true
Although shallowCopy looks the same as the original object, its property b is a shallow copy of the original internal object. This means that nestedObject.b and shallowCopy.b actually refer to the same object in memory.
For deeper replication, you need to use other methods, such as using recursive functions for deep replication, or using existing library functions (such as Lodash's _.cloneDeep) to handle the replication and deconstruction of deep structures.
Events Context
By getting data from serviesAPI and delivery it to all levels of the application
import { useState, createContext, useEffect, useMemo } from 'react' // import mock request and transformed events data import { eventsRequest, eventsTransform } from './eventsService'
// globally use Events Context export const EventsContext = createContext() // 1. create Provider to wrap the app // 2. and provide the certain states // 3. provide initial value export const EventsContextProvider = ({ children }) => { return <EventsContext.Provider value={{ events: [1, 2, 3] }}>{children}</EventsContext.Provider> }
// use Context value in global component import { EventsContext } from '/services' import { useContext } from 'react' const eventsContext = useContext(EventsContext) eventsContext.events // [1,2,3]
Follow the Logic of React ContextAPI:
- In Context.js file, create Context and ContextProvider
- In App.js file, wrap all components with ContextProvider
- In useingContext.js file, use context by useContext hook with Context that imported from step 2
About Step 3, the Mechanism is:
When useContext(EventsContext) is called in a subcomponent, what happens here is:
React will traverse the component tree up until it finds
<EventsContext.Provider>
component.Then, it will use the value attribute of the Provider component, which is the object
{ events: [1, 2, 3] }
you pass.The useContext hook will return this object, so the
eventsContext
variable you get in the component is now a reference to this object.
useState & useEffect
Using state in Context.js file (useState)
Hook them up to be controlled (useEffect)
Once the component is mounted, I retrieve the data
useEffect(() => { retrieveRestaurants() }, [])
const retrieveEvents = () => { // set loading setIsLoading(true) // mimic a slow network setTimeout(() => { // events request has default location eventsRequest() .then(eventsTransform) .then((events) => { setIsLoading(false) setEvents(events) }) .catch((err) => { setIsLoading(false) setError(err) }) }, 2000) }
Loading Indicator
- Use react-native-paper
- Search for ActivityIndicator
Search Feature
- ...
Geocoding in Google
setting up Geocoding service
address words
mutually convertedlongitude and latitude
How to convert logic into code?
In service folder, add location folder
- Location Mock (mimic Geo location data)
- Location Service (send request + transform)
- Location Context (pass location value to whole app)
pass
search function
anddefualt keyword
Create a Search Component (for View)
- Get Context from
locationContext
- Destructuring
search function
andkeyword
- set
keyword
state - return search component
<SearchContainer> <Searchbar placeholder="Search for a location" value={searchKeyword} onSubmitEditing={() => { search(searchKeyword) }} onChangeText={(text) => { setSearchKeyword(text) }} /> </SearchContainer>
onChangeText:
When the content in the text box (i.e. user input) changes, the
onChangeText
callback function will be triggered.This function receives a parameter, that is, the current value of the text box (the content entered by the user).
Whenever the user changes the text input,
onChangeText
will use the current text to call a function to update the state (possibly a React state), which is thesetSearchKeyword
function. This means that thesearchKeyword
status will be updated to the text in the search bar in real time.In this way, the application can capture every change in text input and perform other logic accordingly (for example, real-time search suggestions, form verification, etc.).
onSubmitEditing:
This callback function is triggered when "submit" edits, usually when the user presses the "Search" or "Return" button on the soft keyboard.
When the user completes the input and submits (usually pressing the "Enter" or "Return" key on the virtual keyboard), the executed function does not accept the value of the input box as a parameter. Instead, it takes advantage of the value previously captured by
onChangeText (i.e. searchKeyword status).
When the user submits what they enter in the search bar,
onSubmitEditing
will call the search function and pass in the value currently stored in the searchKeyword. Based on this value, the search function may perform search queries or trigger other search-related operations.
Inadvertently introduce some anti-pattern?
Check and reflect the code that I have written
Avoid infinite loop caused by state and context
Example: in Search component
export const Search = () => { const { keyword, search } = useContext(LocationContext) const [searchKeyword, setSearchKeyword] = useState(keyword) // cause infinite loop useEffect(() => { search(searchKeyword) }, []) return <SearchContainer>//...</SearchContainer> }
Solution: put useEffect in Context file so that it can make Context more intelligent
onSearch
passed out as a function, so that receivesearchKeyword
can be used to updatekeyword
state anduseEffect
watchkeyword
change, and then depend whether re-render or not!export const LocationContextProvider = ({ children }) => { const [keyword, setKeyword] = useState('') const [location, setLocation] = useState(null) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) <!-- IMP --> const onSearch = (searchKeyword) => { setIsLoading(true) setKeyword(searchKeyword) } useEffect(() => { if (!keyword.length) { // don't do anything return } locationRequest(keyword.toLowerCase()) .then(locationTransform) .then((result) => { setIsLoading(false) setLocation(result) console.log(result) }) .catch((err) => { setIsLoading(false) setError(err) console.log(err) }) }, [keyword]) return ( <LocationContext.Provider value={{ isLoading, error, location, <!-- !!!IMP --> search: onSearch, keyword, }} > {children} </LocationContext.Provider> ) }
Stack Navigation
- Restructuring Navigation
- Install the package:
yarn add @react-navigation/stack
- Install the package:
yarn add react-native-gesture-handler
- Splitting Navigation to navigation folder index file, and then in this file export appNavigator with
Tab.Screen
contained stack navigation ofEventsNavigator
- navigation prop in
EventStack.Screen
<EventStack.Navigator> <EventStack.Screen component={EventsScreen}></EventStack.Screen> </EventStack.Navigator>
export const EventsScreen = ({navigation}) => {//...}
- SreenOption configuration
- Setting up Event Detail Navigation
Pressable
vsTouchableOpacity
TransitionPresets
imported from@react-navigation/stack
<RestaurantStack.Navigator headerMode="none" screenOptions={{ ...TransitionPresets.ModalPresentationIOS, }} >
- route prop in
EventsScreen
return ( <Eventstack.Navigator screenOptions={createScreenOptions}> <Eventstack.Screen name="Events" component={EventsScreen} /> <Eventstack.Screen name="EventDetail" component={EventDetailScreen} /> </Eventstack.Navigator> )
export const EventDetailScreen = ({ route }) => { // console.log(route.params); // get the route(EventDatil) payload through route.parms const { event } = route.params return ( <SafeArea> <EventInfo event={event} /> </SafeArea> ) }
- Stack Navigation Summary
Accordion group
List.Accordion
&List.Icon
List.Item
- Scrollable
Hi there! Want to support my work?