React Native – How To Use Redux With React Hooks In React Native Application ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will learn how to use Redux with React Hooks by building a real React Native Application. Redux is a popular React and React Native state management library, meant to be used in complex React and React Native apps where sharing state between multi-level components can get extremely difficult to manage. React Hooks provide us  the ability to use functional components in React or React Native apps. Their ability to provide support to manage a component’s state and handle side-effects offers an alternative to class components.

In this article, let us look at some hooks provided by the react-redux library that provides a way to avoid writing boilerplate code when using the connect() High Order Component.

To understand the use of Redux with React Hooks in React Native application, We will cover the below steps as below :

  1. Configure a New React Native Application
  2. Create Mock Screens
  3. Set Up a Stack Navigator
  4. Create an Overlay Modal With Transparent Background
  5. Navigate to the Modal Screen
  6. Add a Custom Modal With a Transparent Background
  7. Adding a Text Input in the Custom Modal Screen
  8. Add a Custom Header to the List Screen
  9. Change the StatusBar Appearance
  10. Add a List view
  11. Creating a Root Reducer
  12. Configuring a Store
  13. Implement the useSelector Hook
  14. Adding Items to the List by Dispatching an Action Creator
  15. Adding FlatList to Display the Items in the List
  16. Updating the Header
  17. Removing an Item
  18. The final code of the demo application
  19. The final output of the demo application

A famous quote about learning is :

” The purpose of learning is growth, and our minds, unlike our bodies, can continue growing as we continue to live. “

So Let’s begin.


Step 1 – Configure a New React Native Application

To configure a new React Native app, we are going to use expo-cli with a blank template to generate a new app.

expo init projectname

Firstly, we have generated the project, Then we navigate inside the directory and install the following dependencies.

yarn add redux react-redux @react-navigation/native @react-navigation/stack

We are going to use Stack Navigator from the react-navigation library for two different screens in this demo app. For expo-cli, we run the following command to install required dependencies for the navigator to work.

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view


Step 2 – Create Mock Screens

In this section, let us create two screens that the app is going to use to display a list of items and allow the user to add to each item. We create a new directory called src/screens and then create two new ListScreen.js and ModalScreen.js files.

Each of these screen files is going to have some random data to display until the stack navigator is set up.

Here is the code snippet for ListScreen.js :

import React from "react";import { StyleSheet, Text, View } from "react-native";function ListScreen() {return (<View style={styles.container}><Text>List Screen</Text></View>);}const styles = StyleSheet.create({container: {flex: 1,backgroundColor: "#fff",alignItems: "center",justifyContent: "center",},});export default ListScreen;

Here is the code snippet for ModalScreen.js :

import React from "react";import { StyleSheet, Text, View } from "react-native";function ModalScreen() {return (<View style={styles.container}><Text>Modal Screen</Text></View>);}const styles = StyleSheet.create({container: {flex: 1,backgroundColor: "#fff",alignItems: "center",justifyContent: "center",},});export default ModalScreen;


Step 3 – Set Up a Stack Navigator

A Stack Navigator allows the app to transit between different or multiple screens and manages the navigation history. We create a new file called AppNavigator.js inside the src/navigation directory. This file is going to contain all the configurations required to set up a Stack Navigator.

With the recent release of react-navigation version 5, the way to configure a stack navigator has changed. The major highlight of these new changes is the component-based configuration. Navigation patterns are now more component-based, common use cases can now be handled with pre-defined Hooks, the new architecture allowing us to configure and update a screen from within the component itself.

import * as React from "react";import { NavigationContainer } from "@react-navigation/native";import { createStackNavigator } from "@react-navigation/stack";import ListScreen from "../screens/ListScreen";import ModalScreen from "../screens/ModalScreen";

The NavigationContainer is a component provided by the react-navigation library that manages the navigation tree. It contains the navigation state and wraps all the navigator’s structure.

The createStackNavigator is a function that implements a stack navigation pattern. This function returns two React components: Screen and Navigator, that are going to allow us to configure each component screen.

const Stack = createStackNavigator();function MainStackNavigator() {return (<NavigationContainer><Stack.Navigator><Stack.Screen name="List" component={ListScreen} /><Stack.Screen name="Modal" component={ModalScreen} /></Stack.Navigator></NavigationContainer>);}export default MainStackNavigator;

Open the App.js file and import the MainStackNavigator in the root of the app as shown below:

import React from "react";import MainStackNavigator from "./src/navigation/AppNavigator";export default function App() {return <MainStackNavigator />;}

Now, we go the terminal window and execute the command expo start. In the simulator or the real device we are running the Expo client, we are going to notice similar results as shown below:

The first screen in the Stack Navigator is ListScreen, which is shown as above.


Step 4 – Create an Overlay Modal With Transparent Background

The modal can be easily configured with a stack navigator with an overlay of transparent background on the screen as they display it. Since the ListScreen is going to be the first screen and display a list of items, the ModalScreen is going to be a dialog. This dialog appears by clicking a button from the ListScreen in the current application and adds a transparent layer on the screen behind it when opened. The previous screen will be visible underneath this dialog.

This can be done by configuring screenOptions on a Stack Navigator. The react-navigation library provides a way to enable the overlay with a property called cardOverlayEnabled.

Modify AppNavigator.js file as following :

function MainStackNavigator() {return (<NavigationContainer><Stack.Navigatormode="modal"headerMode="none"screenOptions={{cardStyle: { backgroundColor: "transparent" },cardOverlayEnabled: true,cardStyleInterpolator: ({ current: { progress } }) => ({cardStyle: {opacity: progress.interpolate({inputRange: [0, 0.5, 0.9, 1],outputRange: [0, 0.25, 0.7, 1],}),},overlayStyle: {opacity: progress.interpolate({inputRange: [0, 1],outputRange: [0, 0.5],extrapolate: "clamp",}),},}),}}><Stack.Screen name="List" component={ListScreen} /><Stack.Screen name="Modal" component={ModalScreen} /></Stack.Navigator></NavigationContainer>);}

We have to configure the styles of both the screens and add a way for the modal dialog to open from the ListScreen.


Step 5 – Navigate to the Modal Screen

To navigate to the modal screen, let’s add a floating action button with an icon to the ListScreen.js screen component.

This button is going to be touchable and on a single touch is going to navigate to the ModalScreen. The navigation is going to be handled by the navigation prop that can be passed as an argument to the functional component ListScreen. This is only possible because the ListScreen is part of the Stack navigator.

Any screen in a React Native app that utilizes a react-navigation library is a route or a part of a navigation pattern that has access to navigation prop.

Modify the ListScreen.js file as below:

import React from "react";import {StyleSheet,StatusBar,Text,View,TouchableOpacity,} from "react-native";import { Ionicons } from "@expo/vector-icons";function ListScreen({ navigation }) {return (<View style={styles.container}><View style={styles.fabContainer}><TouchableOpacityonPress={() => navigation.navigate("Modal")}style={styles.fabButton}><Ionicons name="ios-add" color="#fff" size={70} /></TouchableOpacity></View></View>);}const styles = StyleSheet.create({container: {flex: 1,backgroundColor: "blue",},fabContainer: {justifyContent: "flex-end",flexDirection: "row",position: "absolute",right: 10,bottom: 20,},fabButton: {backgroundColor: "blue",borderRadius: 35,width: 70,height: 70,alignItems: "center",justifyContent: "center",},});export default ListScreen;

We go back to the simulator device, and we are going to notice the changes. The first thing to notice is the action button floating at the bottom right corner.

On pressing this button, a full-screen modal will open.


Step 6 – Add a Custom Modal With a Transparent Background

In this section, let’s change the behavior of how the modal appears on the ListScreen right now and how we want it to be. As an overlay, we also want it to take the only 1/3rd of the current screen.

This modal is going to have an input field in the future to let the user add items to the list. However, for now, it is going to display a text and a close button.

The close button is going to dismiss the modal when the user wants to go back to the List screen without taking any other action. The close button is going to be placed using position: absolute property and is going to use navigation.goBack() pre-defined method to go back to the List screen.

Here is the complete code for the modal screen at this point. Open ModalScreen.js and modify it.

import React from "react";import { StyleSheet, TouchableOpacity, Text, View } from "react-native";import { Ionicons } from "@expo/vector-icons";function ModalScreen({ navigation }) {return (<View style={styles.container}><View style={styles.innerContainer}><View style={styles.closeButtonContainer}><TouchableOpacitystyle={styles.closeButton}onPress={() => navigation.goBack()}><Ionicons name="ios-close" color="#101010" size={40} /></TouchableOpacity></View><View style={styles.modalContainer}><Text style={{ color: "#444", fontSize: 20 }}>What do you want to do?</Text></View></View></View>);}const styles = StyleSheet.create({container: {flex: 1,},innerContainer: {borderTopLeftRadius: 10,borderTopRightRadius: 10,justifyContent: "flex-end",flexDirection: "row",height: "30%",width: "100%",position: "absolute",bottom: 0,right: 0,backgroundColor: "#fff",},closeButtonContainer: {position: "absolute",alignItems: "flex-end",right: 10,},closeButton: {backgroundColor: "#d3d3d3",borderRadius: 20,width: 40,height: 40,top: 10,alignItems: "center",justifyContent: "center",},modalContainer: {justifyContent: "center",alignItems: "center",position: "absolute",margin: 60,top: 10,left: 50,},});export default ModalScreen;

Here is the output you are going to get in the device after this step:


Step 7 – Adding a Text Input in the Custom Modal Screen

In this section, let’s add a text input component from the react-native core. This is going to allow the user to enter the name of the item they want to add to the list. For now, since we haven’t configured the Redux to manage the app state, let us use the hook useState to manage the component state locally.

Open ModalScreen.js and import TextInput from react-native core.

import {StyleSheet,TouchableOpacity,Text,View,TextInput,} from "react-native";

Next, inside the View that has the style of modalContainer add the following TextInput component as well as a touchable submit button. This touchable button is going to navigate back to the list screen when the user has entered a value in the input field.

<View style={styles.modalContainer}><Text style={{ color: "#444", fontSize: 20 }}>What do you want to do?</Text><TextInputstyle={{height: 50,width: 200,padding: 5,borderColor: "gray",borderBottomWidth: 1,}}numberOfLines={1}onChangeText={(value) => setValue(value)}value={value}clearButtonMode="while-editing"/><TouchableOpacitystyle={{marginTop: 10,backgroundColor: "blue",width: 50,height: 50,\alignItems: "center",justifyContent: "center",borderRadius: 5,}}onPress={() => navigation.navigate("List")}><Ionicons name="ios-arrow-dropright-circle" size={40} color="#fff" /></TouchableOpacity></View>;


Step 8 – Add a Custom Header to the List Screen

Create a new file called Header.js inside the directory src/components. This functional component is going to display the header title in the List screen.

Add the following code snippet to the file. We have just created:

import React from "react";import { View, Text, StyleSheet } from "react-native";function Header(props) {const { title } = props;return (<View style={styles.container}><Text style={styles.text}>{title}</Text></View>);}const styles = StyleSheet.create({container: {alignItems: "center",justifyContent: "center",backgroundColor: "blue",height: 125,paddingTop: 20,},text: {color: "#fff",fontSize: 28,fontWeight: "500",},});export default Header;

Next, we go to the ListScreen.js and import this functional component below the other statements.

// after other import statementsimport Header from '../components/Header'

Then add the component to render before the floating button.

function ListScreen({ navigation }) {return (<View style={styles.container}><Header title={"List"} />{/* rest of the code remains same */}</View>);}


Step 9 – Change the StatusBar Appearance

To change the StatusBar appearance, let us import it from the react-native core API.

import {StyleSheet,StatusBar,Text,View,TouchableOpacity,} from "react-native";

Next, using React Fragment short hand with angle brackets, modify the return statement of ListScreen component as below:

function ListScreen({ navigation }) {return (<><StatusBar barStyle="light-content" /><View style={styles.container}><Header title={"List"} /><View style={styles.fabContainer}><TouchableOpacityonPress={() => navigation.navigate("Modal")}style={styles.fabButton}><Ionicons name="ios-add" color="#fff" size={70} /></TouchableOpacity></View></View></>);}

We will now notice that the Status bar has a white appearance.


Step 10 – Add a List view

In this section, let’s implement the main view that is going to display a list of items. In ListScreen.js, add the following functional component called ListView.

function ListView() {return (<Viewstyle={{backgroundColor: "white",flex: 1,borderTopLeftRadius: 20,borderTopRightRadius: 20,paddingHorizontal: 20,paddingVertical: 20,}}><Text>Here goes list items</Text></View>);}

Then, modify the ListScreen to display it below the Header.

<View style={styles.container}><Header title={"List"} /><ListView />{/* rest of the code remains same */}</View>;

Go to the device, we are running the app, and we are going to notice a major difference in its appearance.


Step 11 – Creating a Root Reducer

In this section, we create a new directory called src/redux/ and inside it, a new file called reducer.js. This file is going to have the definition of action types, action creators and the only reducer we are going to create in this app. This reducer is going to be called rootReducer.

Redux is used to manage the state of the whole application. Therefore, it represents this state by one JavaScript object. Think of this object as read-only (immutable), since we cannot change this state or the object because they represent it in the form of a tree. It requires an action to do so.

Actions are similar to events in Redux. And, they can be triggered in the button press, timers or network requests.

Start by defining an action type as below.

export const ADD_ITEM = 'ADD_ITEM'

Then we define the action creator called addItem that is going to take an item from the user’s input and add it to the list. This is the action creator function that we are going to trigger later.

export const addItem = (item) => ({type: ADD_ITEM,payload: item,});

Define an initial state which is going to have an empty array called itemList. Whenever an action is triggered, the state of the application changes. The handling of the application’s state is done by the reducers.

This initial state is going to be passed as a parameter to the rootReducer. Calling the create action is going to invoke the logic defined for the same action type in the reducer.

Using a reducer, we either want to initiate the current app state or update it, without modifying the whole state on each action trigger. The spread operator returned in the action type ADD_ITEM indicates that.

To update the state, in our case, to add an item object to the itemList array, let us use the contact() that is going to return a new array whenever an item is added to the list. This also satisfies the redux philosophy of not mutating the state directly.

const initialState = {itemList: [],};const rootReducer = (state = initialState, action) => {switch (action.type) {case ADD_ITEM:return {...state,itemList: state.itemList.concat({id: Math.random(),name: action.payload,}),};default:return state;}};export default rootReducer;


Step 12 – Configuring a Store

In this section, we create a new file src/redux/store.js. A store is an object that brings the actions and reducers together. This file is going to implement that.

The store provides and holds the state at the application level instead of individual components. Add the following code snippet to it:

import { createStore } from "redux";import rootReducer from "./reducer";const store = createStore(rootReducer);export default store;

Now, we connect this store to the app, we open App.js file and import the store from this file as well as the High Order Component Provider from react-redux npm package. This HOC helps us to pass the store down to the rest of the components of the current app.

import React from "react";import { Provider as StateProvider } from "react-redux";import store from "./src/redux/store";import MainStackNavigator from "./src/navigation/AppNavigator";export default function App() {return (<StateProvider store={store}><MainStackNavigator /></StateProvider>);}


Step 13 – Implement the useSelector Hook

To access state when managing it with Redux, the useSelector hook is provided in the library. It is similar to mapStateToProps argument that is passed inside the connect(). It allows us to extract data from the Redux store state using a selector function.

The major difference between the hook and the argument (the older way) is that the hook may return any value as a result, not just an object.

Inside ListScreen.js add the following import statement.

import { useSelector } from 'react-redux'

Then, we fetch the listItems array using the hook useSelector inside the ListView component. Also, modify its return statement by displaying a message if the list is empty or not.

function ListView() {const listItems = useSelector((state) => state.itemList);return (<Viewstyle={{backgroundColor: "white",flex: 1,borderTopLeftRadius: 20,borderTopRightRadius: 20,paddingHorizontal: 20,paddingVertical: 20,}}>{listItems.length !== 0 ? (<Text>Contains List items</Text>) : (<Text style={{ fontSize: 30 }}>You list is empty :'(</Text>)}</View>);}


Step 14 – Adding Items to the List by Dispatching an Action Creator

The useDispatch() hook completely refers to the dispatch function from the Redux store. This hook is used only when there is a need to dispatch an action. In the ModalScreen.js to add an item based on the value of TextInput, the state has to be updated. This can be done by triggering the action creator method called addItem defined when creating actions inside redux/reducer.js file.

Start by importing the following statements:

import { useDispatch } from 'react-redux'import { addItem } from '../redux/reducer'

Next, inside the ModalScreen component, we create a helper method called onSaveNote which when triggered on submission of the text input, is going to trigger the action creator as well as take the user back to the List screen.

function ModalScreen({ navigation }) {const [value, setValue] = useState("");const dispatch = useDispatch();const onSaveNote = (value) => {dispatch(addItem(value));navigation.navigate("List");};/* rest of the code remains same */}

Lastly, add this helper method as the value of onPress on the submission button.

<TouchableOpacitystyle={{marginTop: 10,backgroundColor: "blue",width: 50,height: 50,alignItems: "center",justifyContent: "center",borderRadius: 5,}}onPress={() => onSaveNote(value)}><Ionicons name="ios-arrow-dropright-circle" size={40} color="#fff" /></TouchableOpacity>;


Step 15 – Adding FlatList to Display the Items in the List

To display a list of items on List screen, we open the file ListScreen.js and import the FlatList from react-native.

import {StyleSheet,StatusBar,Text,View,TouchableOpacity,FlatList,} from "react-native";

Then, modify the ListView render function as below:

{listItems.length !== 0 ? (<FlatListdata={listItems}keyExtractor={(item) => item.id.toString()}renderItem={({ item }) => (<View style={styles.listItemContainer}><View style={styles.listItemMetaContainer}><Text style={styles.itemTitle} numberOfLines={1}>{item.name}</Text></View></View>)}/>) : (<Text style={{ fontSize: 30 }}>You list is empty :'(</Text>);}


Step 16 – Updating the Header

In this section, using the current app’s state, let us display the number of items in the list to be shown in the header as well. This can be done by using useSelector hook from react-redux.

Modify the file components/Header.js as the following:

import React from "react";import { View, Text, StyleSheet } from "react-native";import { useSelector } from "react-redux";function Header(props) {const { title } = props;const listItems = useSelector((state) => state.itemList);return (<View style={styles.container}><Text style={styles.title}>{title}</Text><Text style={styles.subTitle}>Left: {listItems.length}</Text></View>);}const styles = StyleSheet.create({container: {alignItems: "center",justifyContent: "center",backgroundColor: "blue",height: 125,paddingTop: 20,},title: {color: "#fff",fontSize: 28,fontWeight: "500",},subTitle: {paddingTop: 5,fontSize: 18,color: "#fff",},});export default Header;

Here is the updated header bar when there is one item on the list.


Step 17 – Removing an Item

Since we have gone through the process of understanding how redux hooks work with React Native apps, we try adding a remove item button that is going to delete an item from the list as shown below.

Here is the updated redux/reducer file that has action type REMOVE_ITEM.

export const ADD_ITEM = "ADD_ITEM";export const REMOVE_ITEM = "REMOVE_ITEM";export const addItem = (item) => ({type: ADD_ITEM,payload: item,});export const removeItem = (id) => ({type: REMOVE_ITEM,payload: id,});const initialState = {itemList: [],};const rootReducer = (state = initialState, action) => {switch (action.type) {case ADD_ITEM:return {...state,itemList: state.itemList.concat({id: Math.random(),name: action.payload,}),};case REMOVE_ITEM:return {...state,itemList: state.itemList.filter((item) => item.id !== action.payload),};default:return state;}};export default rootReducer;

Also, here is the updated ListScreen.js where we add the button to remove items with corresponding styles.

To trigger an action, we will have to make use of useDispatch() hook.


Step 18 – The final code of the demo application

Here is the final source code of the demo app:


1. src/redux/reducer.js

export const ADD_ITEM = "ADD_ITEM";export const REMOVE_ITEM = "REMOVE_ITEM";export const addItem = (item) => ({type: ADD_ITEM,payload: item,});export const removeItem = (id) => ({type: REMOVE_ITEM,payload: id,});const initialState = {itemList: [],};const rootReducer = (state = initialState, action) => {switch (action.type) {case ADD_ITEM:return {...state,itemList: state.itemList.concat({id: Math.random(),name: action.payload,}),};case REMOVE_ITEM:return {...state,itemList: state.itemList.filter((item) => item.id !== action.payload),};default:return state;}};export default rootReducer;


2. src/redux/store.js

import { createStore } from "redux";import rootReducer from "./reducer";const store = createStore(rootReducer);export default store;


3. src/components/Header.js

import React from "react";import { View, Text, StyleSheet } from "react-native";import { useSelector } from "react-redux";function Header(props) {const { title } = props;const listItems = useSelector((state) => state.itemList);return (<View style={styles.container}><Text style={styles.title}>{title}</Text><Text style={styles.subTitle}>Left: {listItems.length}</Text></View>);}const styles = StyleSheet.create({container: {alignItems: "center",justifyContent: "center",backgroundColor: "blue",height: 125,paddingTop: 20,},title: {color: "#fff",fontSize: 28,fontWeight: "500",},subTitle: {paddingTop: 5,fontSize: 18,color: "#fff",},});export default Header;


4. src/navigation/AppNavigator.js

import * as React from "react";import { NavigationContainer } from "@react-navigation/native";import { createStackNavigator } from "@react-navigation/stack";import ListScreen from "../screens/ListScreen";import ModalScreen from "../screens/ModalScreen";const Stack = createStackNavigator();function MainStackNavigator() {return (<NavigationContainer><Stack.Navigatormode="modal"headerMode="none"screenOptions={{cardStyle: { backgroundColor: "transparent" },cardOverlayEnabled: true,cardStyleInterpolator: ({ current: { progress } }) => ({cardStyle: {opacity: progress.interpolate({inputRange: [0, 0.5, 0.9, 1],outputRange: [0, 0.25, 0.7, 1],}),},overlayStyle: {opacity: progress.interpolate({inputRange: [0, 1],outputRange: [0, 0.5],extrapolate: "clamp",}),},}),}}><Stack.Screen name="List" component={ListScreen} /><Stack.Screen name="Modal" component={ModalScreen} /></Stack.Navigator></NavigationContainer>);}export default MainStackNavigator;


5. src/screens/ListScreen.js

import React from "react";import {StyleSheet,StatusBar,Text,View,TouchableOpacity,FlatList,} from "react-native";import { Ionicons } from "@expo/vector-icons";import { useSelector, useDispatch } from "react-redux";import { removeItem } from "../redux/reducer";import Header from "../components/Header";function ListScreen({ navigation }) {return (<><StatusBar barStyle="light-content" /><View style={styles.container}><Header title={"List"} /><ListView /><View style={styles.fabContainer}><TouchableOpacityonPress={() => navigation.navigate("Modal")}style={styles.fabButton}><Ionicons name="ios-add" color="#fff" size={70} /></TouchableOpacity></View></View></>);}function ListView() {const listItems = useSelector((state) => state.itemList);console.log({ listItems });const dispatch = useDispatch();return (<Viewstyle={{backgroundColor: "white",flex: 1,borderTopLeftRadius: 20,borderTopRightRadius: 20,paddingHorizontal: 20,paddingVertical: 20,}}>{listItems.length !== 0 ? (<FlatListdata={listItems}keyExtractor={(item) => item.id.toString()}renderItem={({ item }) => (<View style={styles.listItemContainer}><Text style={styles.itemTitle} numberOfLines={1}>{item.name}</Text><TouchableOpacityonPress={() => dispatch(removeItem(item.id))}style={styles.button}><Ionicons name="ios-trash" color="#fff" size={20} /></TouchableOpacity></View>)}/>) : (<Text style={{ fontSize: 30 }}>You list is empty :'(</Text>)}</View>);}const styles = StyleSheet.create({container: {flex: 1,backgroundColor: "blue",},fabContainer: {justifyContent: "flex-end",flexDirection: "row",position: "absolute",right: 10,bottom: 20,},fabButton: {backgroundColor: "blue",borderRadius: 35,width: 70,height: 70,alignItems: "center",justifyContent: "center",},listItemContainer: {flex: 1,flexDirection: "row",paddingTop: 10,paddingBottom: 5,paddingRight: 5,justifyContent: "space-between",width: "100%",borderBottomWidth: 0.25,},itemTitle: {fontSize: 22,fontWeight: "400",},button: {borderRadius: 8,backgroundColor: "#ff333390",padding: 5,},});export default ListScreen;


6. src/screens/ModalScreen.js

import React, { useState, useCallback } from "react";import {StyleSheet,Text,View,TouchableOpacity,TextInput,} from "react-native";import { Ionicons } from "@expo/vector-icons";import { useDispatch } from "react-redux";import { addItem } from "../redux/reducer";function ModalScreen({ navigation }) {const [value, setValue] = useState("");const dispatch = useDispatch();const onSaveNote = (value) => {dispatch(addItem(value));navigation.navigate("List");};return (<View style={styles.container}><View style={styles.innerContainer}><View style={styles.closeButtonContainer}><TouchableOpacitystyle={styles.closeButton}onPress={() => navigation.goBack()}><Ionicons name="ios-close" color="#101010" size={40} /></TouchableOpacity></View><View style={styles.modalContainer}><Text style={{ color: "#444", fontSize: 20 }}>What do you want to do?</Text><TextInputstyle={{height: 50,width: 200,padding: 5,borderColor: "gray",borderBottomWidth: 1,}}numberOfLines={1}onChangeText={(value) => setValue(value)}value={value}clearButtonMode="while-editing"/><TouchableOpacitystyle={{marginTop: 10,backgroundColor: "blue",width: 50,height: 50,alignItems: "center",justifyContent: "center",borderRadius: 5,}}onPress={() => onSaveNote(value)}><Ioniconsname="ios-arrow-dropright-circle"size={40}color="#fff"/></TouchableOpacity></View></View></View>);}const styles = StyleSheet.create({container: {flex: 1,},innerContainer: {borderTopLeftRadius: 10,borderTopRightRadius: 10,justifyContent: "flex-end",flexDirection: "row",height: "30%",width: "100%",position: "absolute",bottom: 0,right: 0,backgroundColor: "#fff",},closeButtonContainer: {position: "absolute",alignItems: "flex-end",right: 10,},closeButton: {backgroundColor: "#d3d3d3",borderRadius: 20,width: 40,height: 40,top: 10,alignItems: "center",justifyContent: "center",},modalContainer: {justifyContent: "center",alignItems: "center",position: "absolute",margin: 60,top: 10,left: 50,},});export default ModalScreen;


7. App.js

import React from "react";import { Provider as StateProvider } from "react-redux";import store from "./src/redux/store";import MainStackNavigator from "./src/navigation/AppNavigator";export default function App() {return (<StateProvider store={store}><MainStackNavigator /></StateProvider>);}

19. The final output of the demo application

Here is the final output of the demo app:

That’s all about in this article.


Conclusion

In this article, we understood how to use Redux with React Hooks by building a real React Native application. This article showed the demo code step by step to use Redux with React Hooks by building a real React Native application. The addition to hooks in react-redux such as useSelector and useDispatch reduces the need to write plentiful boilerplate code and also provides the advantage to use functional components. We also discussed better understanding of the basics of react navigation in real React native application.

Thanks for reading! I hope you enjoyed and learned about Redux and React Hooks practical usage in React Native application. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

React Native Official Website

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

A Short Note – How To Restart/Reset Current Screen In React Native Without Mounting It Again ?

Hello Readers, CoolMonkTechie heartily welcomes you in A Short Note Series (Restart/Reset Current Screen In React Native Without Mounting It Again).

In this note series,  We will learn how to Restart / Reset Current Screen In React Native without mounting it again. React Native does not provide the default refresh component to restart the screen. In some cases, we need to restart or reset the screen again. If we are using React Navigation then we have a choice to mount the screen again and to refresh the screen have a look at Refresh Previous Screen after Going Back in React Navigation but in the normal case, if we need to refresh the screen then react-native-restart can help us by providing RNRestart Component.

So Let’s begin.


To Import the Component

import RNRestart from 'react-native-restart';


To Restart or Reset The Current Screen In React Native

RNRestart.Restart();


Example

In this example, we are going to make a single screen with a setInterval which will update the counter in every second. We will have a button below the counter and on the press of the button, we will refresh the screen.


Example Project Setup

To demonstration of Restart/Reset Current Screen, we have to follow the below steps:

  1. Create a new React Native project
  2. Install the Dependency
  3. Install CocoaPods


1. Create a new React Native project

Assuming that we have node installed, we can use npm to install the react-native-cli command line utility. Open the terminal and go to the workspace and run

npm install -g react-native-cli

Run the following commands to create a new React Native project.

react-native init ProjectName

This will make a project structure with an index file named App.js in your project directory.


2. Install the Dependency 

To install the dependencies, open the terminal and jump into our project

cd ProjectName

Now run the following commands to install the dependencies

npm install react-native-restart --save


3. Install CocoaPods

We need to install pods for the iOS

cd ios && pod install && cd ..


Example Code to Restart/Reset Current Screen In React Native

Now Open App.js in any code editor and replace the code with the following code.

// Restart/Reset Current Screen in React Native Without Mounting it Again

// import React in our code
import React, { useState, useEffect } from "react";

// import all the components we are going to use
import {
SafeAreaView,
Text,
View,
Button,
StyleSheet,
TextInput,
} from "react-native";

import RNRestart from "react-native-restart";

const App = () => {
const [value, setValue] = useState("");

useEffect(() => {
// Resetting default value for the input on restart
setValue("Default Value");
}, []);

const onButtonClick = () => {
RNRestart.Restart();
};

return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.container}>
<View style={styles.container}>
<Text style={styles.heading}>Example of React Native Restart</Text>
<Text style={styles.paragraph}>
Insert any value in Input and Click Restart Screen. You will see
blank TextInput again.
</Text>
<TextInput
placeholder="Please Insert Something"
defaultValue={value}
placeholderTextColor="#808080"
underlineColorAndroid="transparent"
onChangeText={(text) => setValue(text)}
style={styles.textInputStyle}
/>
<View style={{ marginTop: 20 }}>
<Button title="Restart Screen" onPress={onButtonClick} />
</View>
</View>
<Text
style={{
fontSize: 18,
textAlign: "center",
color: "grey",
}}
>
Restart/Reset Current Screen in React Native
</Text>
<Text
style={{
fontSize: 16,
textAlign: "center",
color: "grey",
}}
>
www.coolmonktechie.com
</Text>
</View>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white",
padding: 10,
},
textStyle: {
textAlign: "center",
fontSize: 18,
color: "black",
},
heading: {
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
},
paragraph: {
fontSize: 16,
marginVertical: 16,
textAlign: "center",
},
textInputStyle: {
fontSize: 25,
textAlign: "center",
height: 50,
backgroundColor: "#d6d6d6",
},
});

export default App;


To Run the React Native Example Code

Open the terminal again, and jump into our project using

cd ProjectName

To run the project on an Android Virtual Device or on real debugging device

react-native run-android

or on the iOS Simulator by running (macOS only)

react-native run-ios (macOS only).

The output of example code is as below:

After click the Restart Screen button, the output is as below :


Conclusion

In this note series, we understood how to Restart/Reset Current Screen in React Native Without mounting it again. This article showed the example code to Restart/Reset Current Screen in React Native.

Thanks for reading ! I hope you enjoyed and learned about Restart/Reset Current Screen Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

React Native Official Website

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

iOS – Why Are Architecture Patterns Important In iOS Application ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (Why are Architecture Patterns important in iOS application) .

In this article, we will learn about Architecture Patterns importance in iOS application. Every iOS developer is familiar with issues related to product testing, code refactoring and support via ViewController. We also know the latter as a Massive View Controller. In search for solutions, we’ve delved into a profound investigation of programming patterns for iOS. At some point we realize even this is not enough and time comes for iOS architecture patterns. So we analyzed top-5 patterns, putting them to test in real-life projects. It is important to understand that architectural patterns are not the solution for all problems. They only describe approaches to design mobile applications. Details of realization depend and vary. So we can ask some questions from ourself like these :

  • Who supposed to own networking request: a Model or a Controller?
  • How do I pass a Model into a View Model of a new View?
  • Who creates a new VIPER module: Router or Presenter?

In this article, we cover the following iOS architecture patterns which is used in iOS Application development :

  • Classic MVC
  • Apple’s MVC
  • MVP
  • MVVM
  • VIPER

A famous quote about learning is :

” That is what learning is. You suddenly understand something you’ve understood all your life, but in a new way.”

So Let’s begin.


Why care about choosing the architecture?

Because if we don’t, one day, debugging a huge class with dozens of different things, we’ll find ourself being unable to find and fix any bugs in our class. Naturally, it is hard to keep this class in mind as complete entity, thus, we’ll always be missing some important details. If we are already in this situation with our application, it is likely that:

  • This class is the UIViewController subclass.
  • Our data stored directly in the UIViewController
  • Our UIViews do almost nothing
  • The Model is a dumb data structure
  • Our Unit Tests cover nothing

And this can happen, even despite the fact that we are following Apple’s guidelines and implementing Apple’s MVC pattern, so don’t feel bad. There is something wrong with the Apple’s MVC, but we’ll get back to it later.

Let’s define features of a good architecture:

  1. Balanced distribution of responsibilities among entities with strict roles. The easiest way to defeat complexity is to divide responsibility among multiple entities following the single responsibility principle.
  2. Testability usually comes from the first feature (and don’t worry: it is easy with appropriate architecture).
  3. Ease of use and a low maintenance cost. The least code we have to use, the fewer bugs we have to worry about.


Why is Distribution required?

Distribution keeps a fair load on our brain while we are trying to figure out how things work. If we think the more we develop, the better our brain will adapt to understanding complexity, then we are right. But this ability doesn’t scale linearly and reaches the cap quickly. So the easiest way to defeat complexity is to divide responsibilities among multiple entities following the Single Responsibility Principle.


Why is Testability required?

This is usually not a question for those who already felt gratitude to unit tests, which failed after adding new features or because of refactoring some intricacies of the class. This means the tests saved those developers from finding issues in runtime, which might happen when an app is on a user’s device and the fix takes a week to reach the user.


Why Ease of use?

This does not require an answer, but it is worth mentioning that the best code is the code that has never been written. Therefore, the less code we have, the fewer bugs we have. This means that desire to write less code should never be explained solely by laziness of a developer, and we should not favour a smarter solution closing our eyes to its maintenance cost.


Essential Aspects of Application Architecture

There are five essential aspects of Application Architecture as below :

  • Separation of concern
  • State sharing
  • State propagation
  • View controller communication
  • Parallelism


Aim of Application Architecture

The purpose of Application Architecture is :

  • Fix the massive-view-controller issue
  • Increase testability
  • Improve maintainability
  • Scale with team size


iOS Architecture Patterns

Nowadays we have many options when it comes to architecture design patterns:

  • Classic MVC
  • Apple’s MVC
  • MVP
  • MVVM
  • VIPER

First three of them assume putting the entities of the app into one of 3 categories:

  • Models — responsible for the domain data or a data access layer which manipulates the data, think of ‘Person’ or ‘PersonDataProvider’ classes.
  • Views — responsible for the presentation layer (GUI), for iOS environment think of everything starting with ‘UI’ prefix.
  • Controller/Presenter/ViewModel — the glue or the mediator between the Model and the View responsible for altering the Model by reacting to the user’s actions performed on the View and updating the View with changes from the Model.

Having entities divided allows us to:

  • Understand them better (as we already know)
  • Reuse them (mostly applicable to the View and the Model)
  • Test them independently

So Let’s start with one by one patterns


1. Classic MVC

Here, the View is stateless. It is simply rendered by the Controller once the Model is changed. Think of the web page completely reloaded once. We press on the link to navigate somewhere else. Although it is possible to implement the traditional MVC in iOS application, it doesn’t make much sense because of the architectural problem — it tightly couples all three entities, each entity knows about the other two. This dramatically reduces reusability of each of them — that is not what you want to have in your application. For this reason, we skip even trying to write a canonical MVC example.

Traditional MVC doesn’t seem to be applicable to modern iOS development.


2. Apple’s MVC


Expection

The Controller is a mediator between the View and the Model so that they don’t know about each other. The least reusable is the Controller and this is usually fine for us, since we must have a place for all that tricky business logic that doesn’t fit into the Model.

In theory, it looks very straightforward, but we feel that something is wrong, right? We even heard people abbreviating MVC as the Massive View Controller. View controller offloading became an important topic for the iOS developers. Why does this happen if Apple just took the traditional MVC and improved it a bit?


Reality

Cocoa MVC encourages us to write Massive View Controllers, because they are so involved in View’s life cycle that it’s hard to say they are separate. Although we still have ability to offload some business logic and data transformation to the Model, we have a little choice for offloading work to the View, at most of the times all the responsibility of the View is to send actions to the Controller. The view controller ends up being a delegate and a data source of everything, and is usually responsible for dispatching and cancelling the network requests and… we name it.

How many times have we seen code like this:

var userCell = tableView.dequeueReusableCellWithIdentifier("identifier") as UserCell
userCell.configureWithUser(user)

The cell which is the View configured directly with the Model, so MVC guidelines are violated, but this happens all the time, and usually people don’t feel it is wrong. If we strictly follow the MVC, then we supposed to configure the cell from the controller, and don’t pass the Model into the View, and this will increase the size of our Controller even more.

Cocoa MVC is reasonably unabbreviated as the Massive View Controller.

The problem might not be clear until it comes to the Unit Testing (hopefully, it does in our project). Since our view controller is tightly coupled with the view, it becomes difficult to test because we have to be very creative in mocking views and their life cycle, while writing the view controller’s code in such a way, that our business logic is separated as much as possible from the view layout code.

Let’s have a look on the simple playground example:

/**
 * MVC iOS Design Pattern
 *
 */

import UIKit
import PlaygroundSupport

struct Person { // Model
    let firstName: String
    let lastName: String
}

class GreetingViewController : UIViewController {   // View + Controller
    var person: Person!
    var showGreetingButton: UIButton!
    var greetingLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
        
        self.setupUIElements()
        self.layout()
    }
    
    func setupUIElements() {
        self.title = "Test"
        
        self._setupButton()
        self._setupLabel()
    }
    
    private func _setupButton() {
        self.showGreetingButton = UIButton()
        self.showGreetingButton.setTitle("Click me", for: .normal)
        self.showGreetingButton.setTitle("You badass", for: .highlighted)
        self.showGreetingButton.setTitleColor(UIColor.white, for: .normal)
        self.showGreetingButton.setTitleColor(UIColor.red, for: .highlighted)
        self.showGreetingButton.translatesAutoresizingMaskIntoConstraints = false
        self.showGreetingButton.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)
        self.view.addSubview(self.showGreetingButton)
    }
    
    private func _setupLabel() {
        self.greetingLabel = UILabel()
        self.greetingLabel.textColor = UIColor.white
        self.greetingLabel.textAlignment = .center
        self.greetingLabel.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(self.greetingLabel)
    }
    
    func layout() {
        self._layoutButton()
        self._layoutLabel()
        
        self.view.layoutIfNeeded()
    }
    
    private func _layoutButton() {
        // layout button at the center of the screen
        let cs1 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)
        let cs2 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1.0, constant: 1.0)
        
        self.view.addConstraints([cs1, cs2])
    }
    
    private func _layoutLabel() {
        // layout label at the center, bottom of the screen
        let cs1 = NSLayoutConstraint(item: self.greetingLabel, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)
        let cs2 = NSLayoutConstraint(item: self.greetingLabel, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: -10)
        let cs3 = NSLayoutConstraint(item: self.greetingLabel, attribute: .width, relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 0.70, constant: 0)
        
        self.view.addConstraints([cs1, cs2, cs3])
    }
    
    @objc func didTapButton(sender: UIButton) {
        self.greetingLabel.text = "Hello " + self.person.firstName + " " + self.person.lastName
    }
}

let model = Person(firstName: "Wasin", lastName: "Thonkaew")
let vc = GreetingViewController()
vc.person = model

PlaygroundPage.current.liveView = vc.view

MVC assembling can be performed in the presenting view controller.

This doesn’t seem very testable, right? We can move generation of greeting into the new GreetingModel class and test it separately, but we can’t test any presentation logic (although there is not much of such logic in the example above) inside the GreetingViewController without calling the UIView related methods directly (viewDidLoad, didTapButton) which might cause loading all views, and this is bad for the unit testing.

In fact, loading and testing UIViews on one simulator doesn’t guarantee that it would work fine on the other devices (e.g. iPad), so we’d recommend removing “Host Application” from our Unit Test target configuration and run our tests without our application running on simulator.

The interactions between the View and the Controller aren’t really testable with Unit Tests.

With all that said, it might seems that Cocoa MVC is a pretty bad pattern to choose. But let’s assess it in terms of features defined in the beginning of the article:

  • Distribution —the View and the Model in fact separated, but it tightly couples the View and the Controller.
  • Testability — because of the bad distribution, we’ll probably only test our Model.
  • Ease of use — the least amount of code among other patterns. In addition, everyone is familiar with it, thus, it’s easily maintained even by the unexperienced developers.

Cocoa MVC is the pattern of our choice if we are not ready to invest more time in our architecture, and we feel that something with higher maintenance cost is an overkill for our tiny pet project.

Cocoa MVC is the best architectural pattern in terms of the speed of the development.


3. MVP

MVP (Model View Presenter) is a further development of the MVC pattern. The Controller is replaced by the Presenter. Presenter, unlike Controller in the classic MVC:

  • holds the state of the View.
  • changes the state of the View.
  • handles events of the View.
  • transforms a Domain Model into a ViewModel.

Otherwise, Presenter is like the Controller from the classic MVC:

  • owns the Model.
  • changes the state of the Model (through calling appropriate methods) in response to external stimuli.
  • may contain Application Logic.


MVP – Cocoa MVC’s promises delivered (Passive View Variant)

This diagram doesn’t it look exactly like the Apple’s MVC? Yes, it does, and its name is MVP (Passive View variant). Here, the MVP’s mediator (Presenter) has nothing to do with the life cycle of the view controller, and the View can be mocked easily, so there is no layout code in the Presenter at all, but it updates the View with data and state. 

In terms of the MVP, the UIViewController subclasses are in fact the Views and not the Presenters. This distinction provides superb testability, which comes at a cost of the development speed, because we have to make manual data and event binding, as we can see from the example:

/**
 * MVP iOS Design Pattern
 *
 */

import UIKit
import PlaygroundSupport

struct Person { // Model
    let firstName: String
    let lastName: String
}

protocol GreetingView: class {
    func setGreeting(greeting: String)
}

protocol GreetingViewPresenter {
    init(view: GreetingView, person: Person)
    func showGreeting()
}

class GreetingPresenter : GreetingViewPresenter {
    weak var view: GreetingView?
    let person: Person
    
    required init(view: GreetingView, person: Person) {
        self.view = view
        self.person = person
    }
    
    func showGreeting() {
        let greeting = "Hello " + self.person.firstName + " " + self.person.lastName
        self.view?.setGreeting(greeting: greeting)
    }
}

class GreetingViewController : UIViewController, GreetingView {
    var presenter: GreetingViewPresenter!
    var showGreetingButton: UIButton!
    var greetingLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
        
        self.setupUIElements()
        self.layout()
    }
    
    func setGreeting(greeting: String) {
        self.greetingLabel.text = greeting
    }
    
    func setupUIElements() {
        self.title = "Test"
        
        self._setupButton()
        self._setupLabel()
    }
    
    private func _setupButton() {
        self.showGreetingButton = UIButton()
        self.showGreetingButton.setTitle("Click me", for: .normal)
        self.showGreetingButton.setTitle("You badass", for: .highlighted)
        self.showGreetingButton.setTitleColor(UIColor.white, for: .normal)
        self.showGreetingButton.setTitleColor(UIColor.red, for: .highlighted)
        self.showGreetingButton.translatesAutoresizingMaskIntoConstraints = false
        self.showGreetingButton.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)
        self.view.addSubview(self.showGreetingButton)
    }
    
    private func _setupLabel() {
        self.greetingLabel = UILabel()
        self.greetingLabel.textColor = UIColor.white
        self.greetingLabel.textAlignment = .center
        self.greetingLabel.translatesAutoresizingMaskIntoConstraints = false
        
        self.view.addSubview(self.greetingLabel)
    }
    
    func layout() {
        self._layoutButton()
        self._layoutLabel()
        
        self.view.layoutIfNeeded()
    }
    
    private func _layoutButton() {
        // layout button at the center of the screen
        let cs1 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)
        let cs2 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1.0, constant: 1.0)
        
        self.view.addConstraints([cs1, cs2])
    }
    
    private func _layoutLabel() {
        // layout label at the center, bottom of the screen
        let cs1 = NSLayoutConstraint(item: self.greetingLabel, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)
        let cs2 = NSLayoutConstraint(item: self.greetingLabel, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: -10)
        let cs3 = NSLayoutConstraint(item: self.greetingLabel, attribute: .width, relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 0.70, constant: 0)
        
        self.view.addConstraints([cs1, cs2, cs3])
    }
    
    @objc func didTapButton(sender: UIButton) {
        self.presenter.showGreeting()
    }
}

// Assembling of MVP
// Note: Very important that these following lines will be within View when actually creating normal XCode project and follow design here.
let model = Person(firstName: "Wasin", lastName: "Thonkaew")
let view = GreetingViewController()
let presenter = GreetingPresenter(view: view, person: model)
view.presenter = presenter

PlaygroundPage.current.liveView = view.view

The MVP is the first pattern that reveals the assembly problem, which happens because of having three separate layers. Since we don’t want the View to know about the Model, it is not right to perform assembly in presenting view controller (which is the View), thus we have to do it somewhere else. For example, we can make the app-wide Router service, which will perform assembly and the View-to-View presentation. This issue arises and has to be addressed not only in the MVP but also in all the following patterns.

Let’s look on the features of the MVP:

  • Distribution — we have the most of the responsibilities divided between the Presenter and the Model, with the pretty dumb View (in the example above the Model is dumb as well).
  • Testability — is excellent, we can test most of the business logic because of the dumb View.
  • Easy of use — in our unrealistically simple example, the amount of code is doubled compared to the MVC, but, idea of the MVP is very clear.

MVP in iOS means superb testability and a lot of code.


MVP – With Bindings and Hooters (Supervising Presenter Variant)

There is the other flavour of the MVP — the Supervising Controller MVP. This variant includes direct binding of the View and the Model while the Presenter (The Supervising Controller) still handles actions from the View and is capable of changing the View.

But as we have already learned before, vague responsibility separation is bad, and tight coupling of the View and the Model. That is like how things work in Cocoa desktop development.

Same as with the traditional MVC, we don’t see a point in writing an example for the flawed architecture.


4. MVVM

Despite all the advantages of MVP, with the IDE development and frameworks, it didn’t fit in the automated application development, because it required “manual” work. The next pattern should solve these problems. MVVM (Model View ViewModel) was developed by engineers from Microsoft Ken Cooper and Ted Peters and announced by John Gossman in his blog in 2005.

The purpose of the pattern is separation between the user interface from development and business logic development, and facilitating the application testing using the main features of WPF and Silverlight platforms. Although the pattern of specialization was conceived for Microsoft technology, it can be used in Cocoa / CocoaTouch framework.

In theory, the Model-View-ViewModel looks very good. The View and the Model are already familiar to us, but also the Mediator, represented as the View Model.

It is pretty similar to the MVP:

  • The MVVM treats the view controller as the View
  • There is no tight coupling between the View and the Model

In addition, it does binding like the Supervising version of the MVP; however, this time not between the View and the Model, but between the View and the View Model.

So what is the View Model in the iOS reality? It is basically UIKit independent representation of our View and its state. The View Model invokes changes in the Model and updates itself with the updated Model, and since we have a binding between the View and the View Model, the first is updated accordingly.


Bindings

Bindings come out of a box for the OS X development, but we don’t have them in the iOS toolbox. Of course we have the KVO and notifications, but they aren’t as convenient as bindings.

So, provided we don’t want to write them ourselves, we have two options:

  • One of the KVO based binding libraries like the RZDataBinding or the SwiftBond
  • The full scale functional reactive programming beasts like ReactiveCocoaRxSwift or PromiseKit.

In fact, nowadays, if we hear “MVVM” — we think ReactiveCocoa, and vice versa. Although it is possible to build the MVVM with the simple bindings, ReactiveCocoa (or siblings) will allow us to get most of the MVVM.

There is one bitter truth about reactive frameworks: the great power comes with the great responsibility. It’s really easy to mess up things when we go reactive. In other words, if we do something wrong, we might spend a lot of time debugging the app, so just take a look at this call stack.

In our simple example, the FRF framework or even the KVO is an overkill, instead we’ll explicitly ask the View Model to update using showGreeting method and use the simple property for greetingDidChange callback function.

/*** MVVM iOS Design Pattern**/ import UIKitimport PlaygroundSupportstruct Person { let firstName: String let lastName: String} protocol GreetingViewModelProtocol: class {var greeting: String? { get }var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set }init(person: Person)func showGreeting()}class GreetingViewModel : GreetingViewModelProtocol {let person: Personvar greeting: String? {didSet {self.greetingDidChange?(self)}}var greetingDidChange: ((GreetingViewModelProtocol) -> ())?required init(person: Person) {self.person = person}func showGreeting() {self.greeting = "Hello " + self.person.firstName + " " + self.person.lastName}}class GreetingViewController : UIViewController {var viewModel: GreetingViewModelProtocol? {didSet {self.viewModel?.greetingDidChange = { [unowned self] viewModel inself.greetingLabel.text = viewModel.greeting}}}var showGreetingButton: UIButton!var greetingLabel: UILabel!override func viewDidLoad() {super.viewDidLoad()self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)self.setupUIElements()self.layout()}func setupUIElements() {self.title = "Test"self._setupButton()self._setupLabel()}private func _setupButton() {self.showGreetingButton = UIButton()self.showGreetingButton.setTitle("Click me", for: .normal)self.showGreetingButton.setTitle("You badass", for: .highlighted)self.showGreetingButton.setTitleColor(UIColor.white, for: .normal)self.showGreetingButton.setTitleColor(UIColor.red, for: .highlighted)self.showGreetingButton.translatesAutoresizingMaskIntoConstraints = falseself.showGreetingButton.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)self.view.addSubview(self.showGreetingButton)}private func _setupLabel() {self.greetingLabel = UILabel()self.greetingLabel.textColor = UIColor.whiteself.greetingLabel.textAlignment = .centerself.greetingLabel.translatesAutoresizingMaskIntoConstraints = falseself.view.addSubview(self.greetingLabel)}func layout() {self._layoutButton()self._layoutLabel()self.view.layoutIfNeeded()}private func _layoutButton() { let cs1 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)let cs2 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1.0, constant: 1.0)self.view.addConstraints([cs1, cs2])}private func _layoutLabel() { let cs1 = NSLayoutConstraint(item: self.greetingLabel, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)let cs2 = NSLayoutConstraint(item: self.greetingLabel, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: -10)let cs3 = NSLayoutConstraint(item: self.greetingLabel, attribute: .width, relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 0.70, constant: 0)self.view.addConstraints([cs1, cs2, cs3])}@objc func didTapButton(sender: UIButton) {guard let vm = self.viewModel else { return }vm.showGreeting()}} let model = Person(firstName: "Wasin", lastName: "Thonkaew")let view = GreetingViewController()let viewModel = GreetingViewModel(person: model)view.viewModel = viewModelPlaygroundPage.current.liveView = view.view 

And again back to our feature assessment:

  • Distribution — it is not clear in our tiny example, but, in fact, the MVVM’s View has more responsibilities than the MVP’s View. Because the first one updates its state from the View Model by setting up bindings, when the second one just forwards all events to the Presenter and doesn’t update itself.
  • Testability — the View Model knows nothing about the View, this allows us to test it easily. The View might be also tested, but since it is UIKit dependant we might want to skip it.
  • Easy of use — its has the same amount of code as the MVP in our example, but in the real app where we’d have to forward all events from the View to the Presenter and to update the View manually, MVVM would be much skinnier if we used bindings.

The MVVM is very attractive, since it combines benefits of the aforementioned approaches, and, in addition, it doesn’t require extra code for the View updates because of the bindings on the View side. Nevertheless, testability is still on a good level.


5. VIPER

The examined above architectural patterns have one disadvantage. If we try to divide the architecture into layers, it is likely we will have difficulty with the Presenter or with the View Model. Which layer do they belong to? This question has no simple answer: we can introduce a separate Presentation layer for the Presenter, or it can belong to the Application Logic. The same with MVVM. This ambiguity creates another problem.

It is very difficult to separate the Application Logic from the Domain Model Logic. So often there’s no separation and are in the same layer. Besides, the presence of an Application Logic in a Presenter sometimes makes it difficult to test different Use Cases. Another problem in previous architectures is assembly and navigation. In large projects for several dozens of scenes, this is a responsibility of a separate module Router.

In 2012  a remarkable article was published. The Clean Architecture and several speeches on the subject. Later, in the Mutual Mobile, we’ve adapted a little for iOS, and a new pattern VIPER enters. It is the acronym of View, Interactor, Presenter, Entity, Router–basic components that make up the application. See how they interact below. This gives the LEGO building experience transferred into the iOS app design.

By now, we agree that the granularity in responsibilities is very good. VIPER makes another iteration on the idea of separating responsibilities, and this time we have five layers.

  • View — As with MVP (Passive View), it is a visualization of the data that comes from the Presenter. The View communicates with the Presenter through a protocol at a higher level than the level of UI classes. The Presenter is not aware of specific classes that make up a hierarchy of the View. To share data between the View and the Presenter, it is convenient to use separate structures (i.e. classes that have no methods that could change its state). Only the View and the Presenter know about these classes.
  • Interactor — This layer contains business logic related to the data (Entities) or networking, like creating new instances of entities or fetching them from the server. For those purposes we’ll use some Services and Managers which are not considered as a part of VIPER module but an external dependency.
  • Presenter — This layer contains the UI related (but UIKit independent) business logic, invokes methods on the Interactor.
  • Entities — Our plain data objects, not the data access layer, because that is a responsibility of the Interactor.
  • Router — This layer is responsible for the segues between the VIPER modules. Wireframe and Presenter have the responsibilities for the navigation in VIPER.

Basically, VIPER module can be a one screen or the whole user story of our application — think of authentication, which can be one screen or several related ones. How small are our “LEGO” blocks supposed to be? — It’s up to us.

If we compare it with the other patterns, we’ll see a few differences of the distribution of responsibilities:

  • Model (data interaction) logic shifted into the Interactor with the Entities as dumb data structures.
  • Only the UI representation duties of the Controller/Presenter/ViewModel moved into the Presenter, but not the data altering capabilities.
  • VIPER is the first pattern which explicitly addresses navigation responsibility, which is supposed to be resolved by the Router.

Proper way of doing routing is a challenge for the iOS applications, the other patterns (MVC, MVP, MVVM) simply don’t address this issue.

The example doesn’t cover routing or interaction between modules, as those topics are not covered by the other patterns at all.

/*** VIPER iOS Design Pattern**/import UIKitimport PlaygroundSupportstruct Person { let firstName: Stringlet lastName: String}struct GreetingData {  let greeting: Stringlet subject: String}protocol GreetingProvider {func provideGreetingData()}protocol GreetingOutput: class {func receiveGreetingData(greetingData: GreetingData)}class GreetingInteractor: GreetingProvider {weak var output: GreetingOutput!func provideGreetingData() {let person = Person(firstName: "Wasin", lastName: "Thonkaew")let subject = person.firstName + " " + person.lastNamelet greeting = GreetingData(greeting: "Hello", subject: subject)self.output.receiveGreetingData(greetingData: greeting)}}protocol GreetingViewEventHandler {func didTapShowGreetingButton()}protocol GreetingView: class {func setGreeting(greeting: String)}class GreetingPresenter: GreetingOutput, GreetingViewEventHandler {weak var view: GreetingView!var greetingProvider: GreetingProvider!func didTapShowGreetingButton() {self.greetingProvider.provideGreetingData()}func receiveGreetingData(greetingData: GreetingData) {let greeting = greetingData.greeting + " " + greetingData.subjectself.view.setGreeting(greeting: greeting)}}class GreetingViewController : UIViewController, GreetingView {var eventHandler: GreetingViewEventHandler!var showGreetingButton: UIButton!var greetingLabel: UILabel!override func viewDidLoad() {super.viewDidLoad()self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)self.setupUIElements()self.layout()}func setGreeting(greeting: String) {self.greetingLabel.text = greeting}func setupUIElements() {self.title = "Test"self._setupButton()self._setupLabel()}private func _setupButton() {self.showGreetingButton = UIButton()self.showGreetingButton.setTitle("Click me", for: .normal)self.showGreetingButton.setTitle("You badass", for: .highlighted)self.showGreetingButton.setTitleColor(UIColor.white, for: .normal)self.showGreetingButton.setTitleColor(UIColor.red, for: .highlighted)self.showGreetingButton.translatesAutoresizingMaskIntoConstraints = falseself.showGreetingButton.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)self.view.addSubview(self.showGreetingButton)}private func _setupLabel() {self.greetingLabel = UILabel()self.greetingLabel.textColor = UIColor.whiteself.greetingLabel.textAlignment = .centerself.greetingLabel.translatesAutoresizingMaskIntoConstraints = falseself.view.addSubview(self.greetingLabel)}func layout() {self._layoutButton()self._layoutLabel()self.view.layoutIfNeeded()}private func _layoutButton() { let cs1 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)let cs2 = NSLayoutConstraint(item: self.showGreetingButton, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1.0, constant: 1.0)self.view.addConstraints([cs1, cs2])}private func _layoutLabel() { let cs1 = NSLayoutConstraint(item: self.greetingLabel, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 1.0)let cs2 = NSLayoutConstraint(item: self.greetingLabel, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: -10)let cs3 = NSLayoutConstraint(item: self.greetingLabel, attribute: .width, relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 0.70, constant: 0)self.view.addConstraints([cs1, cs2, cs3])}@objc func didTapButton(sender: UIButton) {self.eventHandler.didTapShowGreetingButton()}}let view = GreetingViewController()let presenter = GreetingPresenter()let interactor = GreetingInteractor()view.eventHandler = presenterpresenter.view = viewpresenter.greetingProvider = interactorinteractor.output = presenterPlaygroundPage.current.liveView = view.view

Yet again, we back to the features:

  • Distribution — undoubtedly, VIPER is a champion in distribution of responsibilities.
  • Testability — no surprises here, better distribution — better testability.
  • Easy of use — finally, two above come in cost of maintainability as we already guessed. We have to write a huge amount of interface for classes with very small responsibilities.


So what about LEGO?

While using VIPER, we might feel like building The Empire State Building from LEGO blocks, and that is a signal that we have a problem. Maybe, it’s too early to adopt VIPER for our application and we should consider something simpler. Some people ignore this and continue shooting out of cannon into sparrows. We assume they believe that their apps will benefit from VIPER at least in the future, even if now the maintenance cost is unreasonably high. If we believe the same, then we’d recommend trying Generamba — a tool for generating VIPER skeletons.

That’s all about in this article.


Conclusion

In this article, we understood Why Are Architecture Patterns important in iOS. This article reviewed some popular ones and compare them in theory and practice going over a few tiny examples.

Thanks for reading! I hope you enjoyed and learned about Architecture patterns importance in iOS Application. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

JavaScript – Understanding Promises In JavaScript

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will learn about promises in javascript. A promise in real life is just an assurance about ‘something.’ So what happens when somebody makes a promise to us? They give us a guarantee based on which we can plan something. Now, the promise can either be kept or broken. So, when we keep a promise, we expect something out of that promise. We can make use of the output of a promise for our further actions or plans. But, when a promise breaks, we would like to know why the person who made the promise was not able to keep up his side of the bargain. JavaScript provides a kind of similar concept of “Promises” for handling the asynchronous calls.

In this article, we will discuss the below items to understand the concepts of promises in JavaScript:

  • What are Promises in JavaScript?
  • When to use Promises in JavaScript?
  • How Promises works in JavaScript?
  • Create a Promise in JavaScript
  • How to consume a Promise in JavaScript?

A famous quote about learning is :

” I am always ready to learn although I do not always like being taught. “

So Let’s begin.


What are Promises in JavaScript?

Promise in JavaScript is an object that holds the future value of an asynchronous operation.

For example, if we are requesting some data from a server, the promise promises us to get that data that we can use in the future.

A promise object can have the following states:

  • Pending: it is an initial state, where the result is not ready, and it is waiting for the asynchronous operation to get finished.
  • Resolved/Fulfilled: it means that performed action completed successfully. i.e., Function returned promised value.
  • Rejected: it means that performed action failed or an error occurred. i.e., function did not return the promised value.


When to use Promises in JavaScript?

Now let’s understand what was the need for the promise in JavaScript, as the async operations would have handled using the callbacks itself. Callback function is used to handle asynchronous execution. A callback function indicates the operation which JavaScript should execute once an asynchronous operation finishes.

Here is the simplest example of a callback function as below:

<html>

	<body> Demonstrating callback in javascript:</br>
    	<script type="text/javascript">
    		function i_take_1_sec() {
                return setTimeout(() => {
                    document.write('I was no: 2 and I take 1 second</br>')
                }, 1000);
            }
            function i_take_10_sec(callback) {
                return setTimeout(() => {
                    document.write('I was no: 1 and I take 10 seconds</br>')
                    callback()
                }, 10000);
            }
            function run (){
                i_take_10_sec(i_take_1_sec);
            }
            run();
        </script>
    </body>

</html>

The output of the above callback function example is :


How Promises works in JavaScript?

To understand how exactly promises works, let us take the example, Consider we are making a promise to our mother saying that we are going to clean up our room by the end of the day. So two possible things can happen either we will be going to clean the room, or we are going not to clean the room and break our promise. Let’s write that promise in the JavaScript.

let promiseCleanRoom = new Promise(function(resolve,reject){
    cleanRoom = true;
    if(cleanRoom){
      resolve('Cleaned the Room');
    }else{
      reject('Broke the promise');
    }
});

The above code block shows how to create the promise. i.e., when this promise executes, then it will give either resolve status or reject status based on the cleanRoom value.

We can call or use the above-created promise as:

 promiseCleanRoom.then((result)=>{
      console.log(result)
  })

In the above snippet, it shows how to utilize the created promise, and there is “.then,” a method that will perform some of the action only when a given promise is fulfilled or resolved. In this case, it will print the result sent by promise when it resolves, i.e., Cleaned the Room.

There is one more case that will happen if the promise got broken or some error occurred in that case. Then we can use the “.catch ” block that will allow handling the broken or instances of error.

promiseCleanRoom.then((result)=>{
      console.log(result)
}).catch((result)=>{
   console.log(result) //will execute if promise is rejected or errored out
})

Suppose, if the promise breaks, then it will execute the catch block by skipping the then block, and output will be “Broke the promise”.


Create a Promise in JavaScript

As we discussed above, A Promise in JavaScript is an object representing the eventual completion or failure of an asynchronous operation. Its syntax looks like below:

const promise = new Promise(function(resolve,reject){

     //do something

});

Here we create a new promise using the Promise constructor, which takes a single argument, a callback function, also known as executor function, which in turn takes two callbacks functions, resolve, and reject

The executor function immediately executes when a promise creates. The promise resolves by calling the resolve() method and is rejected by calling the reject() method.

Let’s try to understand the usage and working of Promise in JavaScript with the help of following code snippet.

<html>

<body> Demonstrating promise in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_1_sec()
    	{ 
    		return new Promise((resolve, reject)=>{
    			setTimeout(() => { 
    				resolve('I was no: 2 and I take 1 second');
    			}, 1000);
    		}) 
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				resolve('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}

    	function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    			setTimeout(() => { 
    				resolve('I was no: 4 and I take 7 second')
    			}, 7000);
    		}) 
    	}

    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
            console.log(result);
        		return i_take_1_sec()
   		})
    		.then((result) => {
            console.log(result);
        		return i_take_5_sec()
    		})
    		.then((result) => {
            console.log(result);
        		return i_take_7_sec()
    		})
    		.then((result)=>{
            console.log(result);
          })
    	}

    	run();

    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

As seen in the above example, each of the functions returns a promise that chains to the next using “.then().” The code flow appears much prettier and understandable in this case.

Now consider a scenario that one of the promises rejects. So, in that scenario, it will raise an error and will not invoke the other chained function calls.

<html>

<body> Demonstrating promise in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_1_sec()
    	{ 
    		return new Promise((resolve, reject)=>{
    			setTimeout(() => { 
    				resolve('I was no: 2 and I take 1 second');
    			}, 1000);
    		}) 
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}

    	function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    			setTimeout(() => { 
    				resolve('I was no: 4 and I take 7 second')
    			}, 7000);
    		}) 
    	}

    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
            console.log(result);
        		return i_take_1_sec()
   		})
    		.then((result) => {
            console.log(result);
        		return i_take_5_sec()
    		})
    		.then((result) => {
            console.log(result);
        		return i_take_7_sec()
    		})
    		.then((result)=>{
            console.log(result);
          })
    	}

    	run();

    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

As we can see from the above screenshot that JavaScript raised an “Uncaught” error after invoking the method “i_take_5_sec,” and no further code statements execute. So, this confirms that, once the promise is “rejected,” it will lead to failure of all the further chained commands.


How to consume a promise in JavaScript?

Promises consume by registering functions using .then, .catch, and .finally methods. A Promise object serves as a link between the executor and the consuming functions, which will receive the result or error, and the consuming functions can use any of the .then, .catch, or .finally methods. Let’s see the usage of all these methods in the below sections:


How to use .then() as a consumer function?

The .then() method invokes when a promise is either resolved or rejected. Its syntax looks like below:

.then(function(result){
        //statements when the promise is resolved successfully
    }, function(error){
        //statements when the prmise was rejected or raised an error
    })

We can understand the primary usage of the “.then()” method with the help of the following figure:

Let comprehend in this way, assume an if-else statement where code in if block will execute when the given condition is true; otherwise, it will execute the else block. Similarly, the “then” method will take two functions as parameters where the first function will run when a promise resolves successfully, or it will execute the second method when a promise rejects or raise an error.

Let’s understand the usage and implementation of the “.then() consumer method,” by modifying the above-written program as follows:

<html>

<body> Demonstrating promise consumer using .then()  method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}
    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
                        console.log(result);
        		return i_take_5_sec()
   		})
    		.then((result)=>{
                   console.log(result);
                 },()=>{
                    console.log('Error Raised')
                 })
    	}

    	run();

    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

We can see from the above screenshot that, as the “i_take_5_sec()” method resulted in the promise to be rejected, so the call flow in the run method invoked the second function, instead of the first function. So, in this way, a user can control the flow of program execution using the “.then()” method depending on the expected outputs of the promise.

But passing two functions as parameters for then method looked somewhat confusing. Therefore, to overcome this, the “.catch” block or function was introduced where the catch block will explicitly handle when there is rejection, or some error has occurred.


How to use .catch() as a consumer function?

The .catch() method invokes when a promise rejects, or some error occurs in the execution. Its syntax looks like below:

Syntax:

.catch(function(error){
        //Statements to handle error raised
    })

The basic usage of the “.catch()” method can be understood with the help of the following figure:

As is evident from the above image, in case of .catch() method specified, it will invoke the “.catch” block when the promise gets rejected.

Lets understand the usage and implementation of the “.catch() consumer method,” by modifying the above-written program as follows:

<html>

<body> Demonstrating promise consumer using .catch() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}
    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
                        console.log(result);
        		return i_take_5_sec()
   		})
    		.then((result)=>{
                    console.log(result);
                }).catch(()=>{
                   console.log('Error Raised')
               })
    	}

    	run();

    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

We can see from the above screenshot that, as the “i_take_5_sec()” method resulted in the promise to be rejected, so the call flow raised the exception, which happened in the .catch() block. Also, as the exception occurred properly, it didn’t block the call flow and still executed the next part in the .then() part resulting from the printing of “Done.”  It makes it clear that using the .catch() block ensures that the further chained calls will still execute, even though one of the intermediate calls resulted in an error or exception.


How to use .finally() as a consumer function?

As we used to have the finally block in a regular try{…} catch{…} of exception handling, there’s finally in promises also. This consumer function always executes when the promise settles: be it resolve or reject. The finally block a good handler for performing cleanup actions, which we always expect to execute. Its syntax looks like below:

.finally(() => {
 // Statements which are expected to be executed always
})

The basic usage of the “.catch()” method can be understood with the help of the following figure:

As we can see from the above picture, the “finally” block will always execute, no matter whether the promise has been resolved or rejected.

Let’s understand the usage and implementation of the “.finally() consumer method,” by modifying the above-written program as follows:

<html>

<body> Demonstrating promise consumer using .finally() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}
    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
            console.log(result);
        		return i_take_5_sec()
   		})
    		.then((result)=>{
            console.log(result);
          }).catch(()=>{
             console.log('Error Raised')
          }).finally(()=>{
             console.log('Completed Execution')
          })
    	}

    	run();

    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

We can see from the above screenshot that, as the “i_take_5_sec()” method resulted in the promise to be rejected, due to which the exception raised and the next .then() method of the “Done” block was not executed. But still, we can see from the output that the finally() block executed. So, it makes it clear that, whether the promise returns a resolved, rejected or and error state, the “finally()” block will always be executed.


How to use Promise.all() as a consumer function?

If we want to execute multiple promises in parallel and want to wait for the completion of all the promises before proceeding further, we can use the “.all” function provided by the Promises in JavaScript. It takes an array of promises function and executes all functions simultaneously / parallelly and wait until all promises are either resolve or reject. Its syntax looks like below:

Promise.all([array of promises]);

Let’s understand the usage of “Promise.all” with the help of the following example:

<html>

<body> Demonstrating promise all() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
               console.log('I was no: 1 and I take 10 second')
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 2 and I take 5 second')
    				resolve('I was no: 2 and I take 5 second')
    			}, 5000); 
    		})
    	}

      function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 3 and I take 7 second')
    				resolve('I was no: 3 and I take 7 second')
    			}, 7000); 
    		})
    	}
    
    	function run()
    	{
    		Promise.all([i_take_10_sec(),i_take_5_sec(),i_take_7_sec()]).then(()=>{
             console.log("All finished");
          })
    	}

    	run();
    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

As we can see that all the promises are executing simultaneously and will wait until all promises either resolve or reject.

we aware that Promise.all() doesn’t ensure any ordering of promises. It just executes all of the promises in parallel.


How to use Promise.race() as a consumer function?

If we want to execute multiple promises in parallel but don’t want to wait for the completion of all the promises before proceeding further, we can use the “.race” function provided by the Promises in JavaScript. It just waits for completion of any one promise, which returns first. It will take an array of promises function and execute all functions simultaneously and wait until any one of the promises is either resolve or reject. Its syntax looks like below:

Promise.race([array of promises])

Let’s understand the usage of “Promise.race” with the help of the following example:

<html>

<body> Demonstrating promise race() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
               console.log('I was no: 1 and I take 10 second')
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 2 and I take 5 second')
    				resolve('I was no: 2 and I take 5 second')
    			}, 5000); 
    		})
    	}

      function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 3 and I take 7 second')
    				resolve('I was no: 3 and I take 7 second')
    			}, 7000); 
    		})
    	}
    
    	function run()
    	{
    		Promise.race([i_take_10_sec(),i_take_5_sec(),i_take_7_sec()]).then(()=>{
             console.log("All finished");
          })
    	}

    	run();
    </script>
</body>

</html>

The Developer Tools output of the above example code snippet is :

In the above example, we can see that as soon as one promise(i_take_5 sec) resolves, it exits from then function.

That’s all about in this article.


Conclusion

In this article, We understood about Promises in JavaScript. We conclude that :

  • Promises can handle the asynchronous calls in JavaScript.
  • A promise will be “pending” when executed and will result in “resolved” or “rejected,” depending on the response of the asynchronous call.
  • Promises avoid the problem of “callback hell,” which happens due to nested callback functions.

Thanks for reading !! I hope you enjoyed and learned about Promises Concept in javascript. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – Understanding Kotlin Style Guide

Hello Readers, CoolMonkTechie heartily welcomes you in this article (Understanding Kotlin Style Guide).

In this article, We will learn about the Kotlin Style Guide. This article serves as the complete definition of Google’s Android coding standards for source code in the Kotlin Programming Language. A Kotlin source file is described as being in Google Android Style if and only if it adheres to the rules herein.

Like other programming style guides, the issues covered span not only aesthetic issues of formatting, but other types of conventions or coding standards as well. However, this article focuses primarily on the hard-and-fast rules that we follow universally, and avoids giving advice that isn’t clearly enforceable (whether by human or tool).

A famous quote about learning is :

” We now accept the fact that learning is a lifelong process of keeping abreast of change. And the most pressing task is to teach people how to learn. “

So Let’s begin.


1. Source Files

All source files must be encoded as UTF-8.


1.1. Naming

If a source file contains only a single top-level class, the file name should reflect the case-sensitive name plus the .kt extension. Otherwise, if a source file contains multiple top-level declarations, choose a name that describes the contents of the file, apply PascalCase, and append the .kt extension.

// MyClass.kt
class MyClass { }
// Bar.kt
class Bar { }
fun Runnable.toBar(): Bar = // …
// Map.kt
fun <T, O> Set<T>.map(func: (T) -> O): List<O> = // …
fun <T, O> List<T>.map(func: (T) -> O): List<O> = // …


1.2. Special Characters


1.2.1. Whitespace Characters

Aside from the line terminator sequence, the ASCII horizontal space character (0x20) is the only whitespace character that appears anywhere in a source file. This implies that:

  • All other whitespace characters in string and character literals are escaped.
  • Tab characters are not used for indentation.


1.2.2. Special Escape Sequences

For any character that has a special escape sequence (\b\n\r\t\'\"\\, and \$), that sequence is used rather than the corresponding Unicode (e.g., \u000a) escape.


1.2.3. Non-ASCII Characters

For the remaining non-ASCII characters, either the actual Unicode character (e.g., ) or the equivalent Unicode escape (e.g., \u221e) is used. The choice depends only on which makes the code easier to read and understand. Unicode escapes are discouraged for printable characters at any location and are strongly discouraged outside of string literals and comments.

ExampleDiscussion
val unitAbbrev = "μs"Best: perfectly clear even without a comment.
val unitAbbrev = "\u03bcs" // μsPoor: there’s no reason to use an escape with a printable character.
val unitAbbrev = “\u03bcs”`Poor: the reader has no idea what this is.
return "\ufeff" + contentGood: use escapes for non-printable characters, and comment if necessary.


1.3. Structure

.kt file comprises the following, in order:

  • Copyright and/or license header (optional)
  • File-level annotations
  • Package statement
  • Import statements
  • Top-level declarations

Exactly one blank line separates each of these sections.


1.3.1. Copyright / License

If a copyright or license header belongs in the file it should be placed at the immediate top in a multi-line comment.

/*
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
 

Do not use a KDoc-style or single-line-style comment.

/**
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
// Copyright 2017 Google, Inc.
//
// ...


1.3.2. File-level Annotations

Annotations with the “file” use-site target are placed between any header comment and the package declaration.


1.3.3. Package Statement

The package statement is not subject to any column limit and is never line-wrapped.


1.3.4. Import Statements

Import statements for classes, functions, and properties are grouped together in a single list and ASCII sorted.

Wildcard imports (of any type) are not allowed.

Similar to the package statement, import statements are not subject to a column limit and they are never line-wrapped.


1.3.5. Top-level Declarations

.kt file can declare one or more types, functions, properties, or type aliases at the top-level.

The contents of a file should be focused on a single theme. Examples of this would be a single public type or a set of extension functions performing the same operation on multiple receiver types. Unrelated declarations should be separated into their own files and public declarations within a single file should be minimized.

No explicit restriction is placed on the number nor order of the contents of a file.

Source files are usually read from top-to-bottom meaning that the order, in general, should reflect that the declarations higher up will inform understanding of those farther down. Different files may choose to order their contents differently. Similarly, one file may contain 100 properties, another 10 functions, and yet another a single class.

What is important is that each class uses some logical order, which its maintainer could explain if asked. For example, new functions are not just habitually added to the end of the class, as that would yield “chronological by date added” ordering, which is not a logical ordering.


1.3.6. Class Member Ordering

The order of members within a class follow the same rules as the top-level declarations.


2. Formatting


2.1. Braces

Braces are not required for when branches and if statement bodies which have no else if/else branches and which fit on a single line.

if (string.isEmpty()) return

when (value) {
    0 -> return
    // …
}

Braces are otherwise required for any ifforwhen branch, do, and while statements, even when the body is empty or contains only a single statement.

if (string.isEmpty())
    return  // WRONG!

if (string.isEmpty()) {
    return  // Okay
}


2.1.1. Non-empty Blocks

The braces follow the Kernighan and Ritchie style (“Egyptian brackets”) for nonempty blocks and block-like constructs:

  • Firstly, No line break before the opening brace.
  • Secondly, Line break after the opening brace.
  • Thirdly, Line break before the closing brace.
  • And finally, Line break after the closing brace, only if that brace terminates a statement or terminates the body of a function, constructor, or named class. For example, there is no line break after the brace if it is followed by else or a comma.

return Runnable {
    while (condition()) {
        foo()
    }
}

return object : MyClass() {
    override fun foo() {
        if (condition()) {
            try {
                something()
            } catch (e: ProblemException) {
                recover()
            }
        } else if (otherCondition()) {
            somethingElse()
        } else {
            lastThing()
        }
    }
}


2.1.2. Empty Blocks

An empty block or block-like construct must be in K&R style.

try {
    doSomething()
} catch (e: Exception) {} // WRONG!
try {
    doSomething()
} catch (e: Exception) {
} // Okay


2.1.3. Expressions

An if/else conditional that is used as an expression may omit braces only if the entire expression fits on one line.

val value = if (string.isEmpty()) 0 else 1  // Okay
val value = if (string.isEmpty())  // WRONG!
    0
else
    1
val value = if (string.isEmpty()) { // Okay
    0
} else {
    1
}


2.1.4. Indentation

Each time a new block or block-like construct is opened, the indent increases by four spaces. When the block ends, the indent returns to the previous indent level. The indent level applies to both code and comments throughout the block.


2.1.5. One Statement Per Line

Each statement is followed by a line break. Semicolons are not used.


2.1.6. Line Wrapping

Code has a column limit of 100 characters. Except as noted below, any line that would exceed this limit must be line-wrapped, as explained below.

Exceptions:

  • Lines where obeying the column limit is not possible (for example, a long URL in KDoc)
  • package and import statements
  • Command lines in a comment that may be cut-and-pasted into a shell


2.1.7. Where to break

The prime directive of line-wrapping is: prefer to break at a higher syntactic level. Also:

  • When a line is broken at an operator or infix function name, the break comes after the operator or infix function name.
  • When a line is broken at the following “operator-like” symbols, the break comes before the symbol:
    • The dot separator (.?.).
    • The two colons of a member reference (::).
  • A method or constructor name stays attached to the open parenthesis (() that follows it.
  • A comma (,) stays attached to the token that precedes it.
  • A lambda arrow (->) stays attached to the argument list that precedes it.


2.1.8. Functions

When a function signature does not fit on a single line, break each parameter declaration onto its own line. Parameters defined in this format should use a single indent (+4). The closing parenthesis ()) and return type are placed on their own line with no additional indent.

fun <T> Iterable<T>.joinToString(
    separator: CharSequence = ", ",
    prefix: CharSequence = "",
    postfix: CharSequence = ""
): String {
    // …
}


2.1.9. Expression Functions

When a function contains only a single expression it can be represented as an expression function.

override fun toString(): String {
    return "Hey"
}
override fun toString(): String = "Hey"

The only time an expression function should wrap to multiple lines is when it opens a block.

fun main() = runBlocking {
  // …
}

Otherwise, if an expression function grows to require wrapping, use a normal function body, a return declaration, and normal expression wrapping rules instead.


2.1.10. Properties

When a property initializer does not fit on a single line, break after the equals sign (=) and use an indent.

private val defaultCharset: Charset? =
        EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)

Properties declaring a get and/or set function should place each on their own line with a normal indent (+4). Format them using the same rules as functions.

var directory: File? = null
    set(value) {
        // …
    }

Read-only properties can use a shorter syntax which fits on a single line.

val defaultExtension: String get() = "kt"


2.2. Whitespace


2.2.1. Vertical

A single blank line appears:

  • Between consecutive members of a class: properties, constructors, functions, nested classes, etc.
    • Exception: A blank line between two consecutive properties (having no other code between them) is optional. Such blank lines are used as needed to create logical groupings of properties and associate properties with their backing property, if present.
    • Exception: Blank lines between enum constants are covered below.
  • Between statements, as needed to organize the code into logical subsections.
  • Optionally before the first statement in a function, before the first member of a class, or after the last member of a class (neither encouraged nor discouraged).

Multiple consecutive blank lines are permitted, but not encouraged or ever required.


2.2.2. Horizontal

Beyond where required by the language or other style rules, and apart from literals, comments, and KDoc, a single ASCII space also appears in the following places only:

  • Separating any reserved word, such as iffor, or catch from an open parenthesis (() that follows it on that line.
// WRONG!
for(i in 0..1) {
}
// Okay
for (i in 0..1) {
}
  • Separating any reserved word, such as else or catch, from a closing curly brace (}) that precedes it on that line.
// WRONG!
}else {
}
// Okay
} else {
}
  • Before any open curly brace ({).
// WRONG!
if (list.isEmpty()){
}
// Okay
if (list.isEmpty()) {
}
  • Before a colon (:) only if used in a class declaration for specifying a base class or interfaces, or when used in a where clause for generic constraints.
// WRONG!
class Foo: Runnable
// Okay
class Foo : Runnable
// WRONG
fun <T: Comparable> max(a: T, b: T)
// Okay
fun <T : Comparable> max(a: T, b: T)
// WRONG
fun <T> max(a: T, b: T) where T: Comparable<T>
// Okay
fun <T> max(a: T, b: T) where T : Comparable<T>
  • After a comma (,) or colon (:).
// WRONG!
val oneAndTwo = listOf(1,2)
// Okay
val oneAndTwo = listOf(1, 2)
// WRONG!
class Foo :Runnable
// Okay
class Foo : Runnable
  • On both sides of the double slash (//) that begins an end-of-line comment. Here, multiple spaces are allowed, but not required.
// WRONG!
var debugging = false//disabled by default
// Okay
var debugging = false // disabled by default
  • On both sides of any binary operator.
// WRONG!
val two = 1+1
// Okay
val two = 1 + 1

This also applies to the following “operator-like” symbols:

  • the arrow in a lambda expression (->).
// WRONG!
ints.map { value->value.toString() }
// Okay
ints.map { value -> value.toString() }

But not:

  • the two colons (::) of a member reference.
// WRONG!
val toString = Any :: toString
// Okay
val toString = Any::toString
  • the dot separator (.).
// WRONG
it . toString()
// Okay
it.toString()
  • the range operator (..).
// WRONG
 for (i in 1 .. 4) print(i)
 
 // Okay
 for (i in 1..4) print(i)

This rule is never interpreted as requiring or forbidding additional space at the start or end of a line; it addresses only interior space.


2.3. Specific Constructs


2.3.1. Enum Classes

An enum with no functions and no documentation on its constants may optionally be formatted as a single line.

enum class Answer { YES, NO, MAYBE }

When the constants in an enum are placed on separate lines, a blank line is not required between them except in the case where they define a body.

enum class Answer {
    YES,
    NO,

    MAYBE {
        override fun toString() = """¯\_(ツ)_/¯"""
    }
}

Since enum classes are classes, all other rules for formatting classes apply.


2.3.2. Annotations

Member or type annotations are placed on separate lines immediately prior to the annotated construct.

@Retention(SOURCE)
@Target(FUNCTION, PROPERTY_SETTER, FIELD)
annotation class Global

Annotations without arguments can be placed on a single line.

@JvmField @Volatile
var disposable: Disposable? = null

When only a single annotation without arguments is present, it may be placed on the same line as the declaration.

@Volatile var disposable: Disposable? = null

@Test fun selectAll() {
    // …
}

@[...] syntax may only be used with an explicit use-site target, and only for combining 2 or more annotations without arguments on a single line.

@field:[JvmStatic Volatile]
var disposable: Disposable? = null


2.3.3. Implicit Return/Property Types

If an expression function body or a property initializer is a scalar value or the return type can be clearly inferred from the body then it can be omitted.

override fun toString(): String = "Hey"
// becomes
override fun toString() = "Hey"
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png")
// becomes
private val ICON = IconLoader.getIcon("/icons/kotlin.png")

When writing a library, retain the explicit type declaration when it is part of the public API.


2.4. Naming

Identifiers use only ASCII letters and digits, and, in a small number of cases noted below, underscores. Thus each valid identifier name is matched by the regular expression \w+.

Special prefixes or suffixes, like those seen in the examples name_mNames_name, and kName, are not used except in the case of backing properties.


2.4.1. Package Names

Package names are all lowercase, with consecutive words simply concatenated together (no underscores).

// Okay
package com.example.deepspace
// WRONG!
package com.example.deepSpace
// WRONG!
package com.example.deep_space


2.4.2. Type Names

Class names are written in PascalCase and are typically nouns or noun phrases. For example, Character or ImmutableList. Interface names may also be nouns or noun phrases (for example, List), but may sometimes be adjectives or adjective phrases instead (for example Readable).

Test classes are named starting with the name of the class they are testing, and ending with Test. For example, HashTest or HashIntegrationTest.


2.4.3. Function Names

Function names are written in camelCase and are typically verbs or verb phrases. For example, sendMessage or stop.

Underscores are permitted to appear in test function names to separate logical components of the name.

@Test fun pop_emptyStack() {
    // …
}

Functions annotated with @Composable that return Unit are PascalCased and named as nouns, as if they were types.

@Composable
fun NameTag(name: String) {
    // …
}


2.4.4. Constant Names

Constant names use UPPER_SNAKE_CASE: all uppercase letters, with words separated by underscores. But what is a constant, exactly?

Constants are val properties with no custom get function, whose contents are deeply immutable, and whose functions have no detectable side-effects. This includes immutable types and immutable collections of immutable types as well as scalars and string if marked as const. If any of an instance’s observable state can change, it is not a constant. Merely intending to never mutate the object is not enough.

const val NUMBER = 5
val NAMES = listOf("Alice", "Bob")
val AGES = mapOf("Alice" to 35, "Bob" to 32)
val COMMA_JOINER = Joiner.on(',') // Joiner is immutable
val EMPTY_ARRAY = arrayOf()

These names are typically nouns or noun phrases.

Constant values can only be defined inside of an object or as a top-level declaration. Values otherwise meeting the requirement of a constant but defined inside of a class must use a non-constant name.

Constants which are scalar values must use the const modifier.


2.4.5. Non-constant Names

Non-constant names are written in camelCase. These apply to instance properties, local properties, and parameter names.

val variable = "var"
val nonConstScalar = "non-const"
val mutableCollection: MutableSet = HashSet()
val mutableElements = listOf(mutableInstance)
val mutableValues = mapOf("Alice" to mutableInstance, "Bob" to mutableInstance2)
val logger = Logger.getLogger(MyClass::class.java.name)
val nonEmptyArray = arrayOf("these", "can", "change")

These names are typically nouns or noun phrases.


2.4.6. Backing Properties

When a backing property is needed, its name should exactly match that of the real property except prefixed with an underscore.

private var _table: Map? = null

val table: Map
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError()
    }


2.4.7. Type Variable Names

Each type variable is named in one of two styles:

  • A single capital letter, optionally followed by a single numeral (such as ETXT2).
  • A name in the form used for classes, followed by the capital letter T (such as RequestTFooBarT).


2.4.8. Camel Case

Sometimes there is more than one reasonable way to convert an English phrase into camel case, such as when acronyms or unusual constructs like “IPv6” or “iOS” are present. To improve predictability, use the following scheme.

Beginning with the prose form of the name:

  1. Convert the phrase to plain ASCII and remove any apostrophes. For example, “Müller’s algorithm” might become “Muellers algorithm”.
  2. Divide this result into words, splitting on spaces and any remaining punctuation (typically hyphens). Recommended: if any word already has a conventional camel-case appearance in common usage, split this into its constituent parts (e.g., “AdWords” becomes “ad words”). Note that a word such as “iOS” is not really in camel case per se; it defies any convention, so this recommendation does not apply.
  3. Now lowercase everything (including acronyms), then do one of the following:
    • Uppercase the first character of each word to yield pascal case.
    • Uppercase the first character of each word except the first to yield camel case.
  4. Finally, join all the words into a single identifier.

We note that the casing of the original words is almost entirely disregarded.

Prose formCorrectIncorrect
“XML Http Request”XmlHttpRequestXMLHTTPRequest
“new customer ID”newCustomerIdnewCustomerID
“inner stopwatch”innerStopwatchinnerStopWatch
“supports IPv6 on iOS”supportsIpv6OnIossupportsIPv6OnIOS
“YouTube importer”YouTubeImporterYoutubeImporter*

(* Acceptable, but not recommended.)


2.5. Documentation


2.5.1. Formatting

The basic formatting of KDoc blocks is seen in this example:

/**
 * Multiple lines of KDoc text are written here,
 * wrapped normally…
 */
fun method(arg: String) {
    // …
}

…or in this single-line example:

/** An especially short bit of KDoc. */

The basic form is always acceptable. The single-line form may be substituted when the entirety of the KDoc block (including comment markers) can fit on a single line. Note that this only applies when there are no block tags such as @return.


2.5.2. Paragraphs

One blank line—that is, a line containing only the aligned leading asterisk (*)—appears between paragraphs, and before the group of block tags if present.


2.5.3. Block Tags

Any of the standard “block tags” that are used appear in the order @constructor@receiver@param@property@return@throws@see, and these never appear with an empty description. When a block tag doesn’t fit on a single line, continuation lines are indented 4 spaces from the position of the @.


2.5.4. Summary Fragment

Each KDoc block begins with a brief summary fragment. This fragment is very important: it is the only part of the text that appears in certain contexts such as class and method indexes.

This is a fragment–a noun phrase or verb phrase, not a complete sentence. It does not begin with “A `Foo` is a...“, or “This method returns...“, nor does it have to form a complete imperative sentence like “Save the record.“. However, the fragment is capitalized and punctuated as if it were a complete sentence.


2.5.5. Usage

At the minimum, KDoc is present for every public type, and every public or protected member of such a type, with a few exceptions noted below.


2.5.5.1. Exception: Self-explanatory Functions

KDoc is optional for “simple, obvious” functions like getFoo and properties like foo, in cases where there really and truly is nothing else worthwhile to say but “Returns the foo”.

It is not appropriate to cite this exception to justify omitting relevant information that a typical reader might need to know. For example, for a function named getCanonicalName or property named canonicalName, don’t omit its documentation (with the rationale that it would say only /** Returns the canonical name. */) if a typical reader may have no idea what the term “canonical name” means!

2.5.5.2. Exception: Overrides

KDoc is not always present on a method that overrides a supertype method.

That’s all about in this article.


Conclusion

In this article, We understood about Kotlin Style Guide for Android application development. This article served as the complete definition of Google’s Android coding standards for source code in the Kotlin Programming Language. We discussed about Source code and formatting style guideline standard for Kotlin which is used in android application development.

Thanks for reading ! I hope you enjoyed and learned about Kotlin Style Guide concepts in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – How To Apply Common Kotlin Patterns In Android Application ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Apply Common Kotlin Patterns In Android Application ?)

In this article, We will learn how to apply common Kotlin patterns in Android apps. This article will focus on some of the most useful aspects of the Kotlin language when developing for Android.

A famous quote about learning is :

” Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young. The greatest thing in life is to keep your mind young. “

So Let’s begin.


Work with fragments

In this sections, we use Fragment examples to highlight some of Kotlin’s best features as below:


Inheritance

We can declare a class in Kotlin with the class keyword. In the following example, LoginFragment is a subclass of Fragment. We can indicate inheritance by using the : operator between the subclass and its parent:

class LoginFragment : Fragment()

In this class declaration, LoginFragment is responsible for calling the constructor of its superclass, Fragment.

Within LoginFragment, we can override a number of lifecycle callbacks to respond to state changes in our Fragment. To override a function, use the override keyword, as shown in the following example:

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.login_fragment, container, false)
}

To reference a function in the parent class, use the super keyword, as shown in the following example:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
}


Nullability and Initialization

In the previous examples, some of the parameters in the overridden methods have types suffixed with a question mark ?. This indicates that the arguments passed for these parameters can be null. Be sure to handle their nullability safely.

In Kotlin, we must initialize an object’s properties when declaring the object. This implies that when we obtain an instance of a class, we can immediately reference any of its accessible properties. The View objects in a Fragment, however, aren’t ready to be inflated until calling Fragment#onCreateView, so we need a way to defer property initialization for a View.

The lateinit lets us defer property initialization. When using lateinit, we should initialize our property as soon as possible.

The following example demonstrates using lateinit to assign View objects in onViewCreated:

class LoginFragment : Fragment() {

    private lateinit var usernameEditText: EditText
    private lateinit var passwordEditText: EditText
    private lateinit var loginButton: Button
    private lateinit var statusTextView: TextView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        usernameEditText = view.findViewById(R.id.username_edit_text)
        passwordEditText = view.findViewById(R.id.password_edit_text)
        loginButton = view.findViewById(R.id.login_button)
        statusTextView = view.findViewById(R.id.status_text_view)
    }

    ...
}

We aware that if we access a property before it is initialized, Kotlin throws an UninitializedPropertyAccessException.


SAM Conversion

We can listen for click events in Android by implementing the OnClickListener interface. Button objects contain a setOnClickListener() function that takes in an implementation of OnClickListener.

OnClickListener has a single abstract method, onClick(), that we must implement. Because setOnClickListener() always takes an OnClickListener as an argument, and because OnClickListener always has the same single abstract method, this implementation can be represented using an anonymous function in Kotlin. This process is known as Single Abstract Method conversion, or SAM conversion.

SAM conversion can make our code considerably cleaner. The following example shows how to use SAM conversion to implement an OnClickListener for a Button:

loginButton.setOnClickListener {
    val authSuccessful: Boolean = viewModel.authenticate(
            usernameEditText.text.toString(),
            passwordEditText.text.toString()
    )
    if (authSuccessful) {
        // Navigate to next screen
    } else {
        statusTextView.text = requireContext().getString(R.string.auth_failed)
    }
}

The code within the anonymous function passed to setOnClickListener() executes when a user clicks loginButton.


Companion Objects

The Companion objects provide a mechanism for defining variables or functions that linked conceptually to a type but do not tie to a particular object. Companion objects are similar to using Java’s static keyword for variables and methods.

In the following example, TAG is a String constant. We don’t need a unique instance of the String for each instance of LoginFragment, so we should define it in a companion object:

class LoginFragment : Fragment() {

    ...

    companion object {
        private const val TAG = "LoginFragment"
    }
}

We could define TAG at the top level of the file, but the file might also have a large number of variables, functions, and classes that are also defined at the top level. Companion objects help to connect variables, functions, and the class definition without referring to any particular instance of that class.


Property Delegation

When initializing properties, we might repeat some of Android’s more common patterns, such as accessing a ViewModel within a Fragment. To avoid excess duplicate code, we can use Kotlin’s property delegation syntax.

private val viewModel: LoginViewModel by viewModels()

Property delegation provides a common implementation that we can reuse throughout our app. Android KTX provides some property delegates for us. viewModels, for example, retrieves a ViewModel that is scoped to the current Fragment.

Property delegation uses reflection, which adds some performance overhead. The tradeoff is a concise syntax that saves development time.


Nullability

Kotlin provides strict nullability rules that maintain type-safety throughout our app. In Kotlin, references to objects cannot contain null values by default. To assign a null value to a variable, we must declare a nullable variable type by adding ? to the end of the base type.

As an example, the following expression is illegal in Kotlin. name is of type String and isn’t nullable:

val name: String = null

To allow a null value, we must use a nullable String type, String?, as shown in the following example:

val name: String? = null


Interoperability

Kotlin’s strict rules make our code safer and more concise. These rules lower the chances of having a NullPointerException that would cause our app to crash. Moreover, they reduce the number of null checks, we need to make in our code.

Often, we must also call into non-Kotlin code when writing an Android app, as most Android APIs are written in the Java programming language.

Nullability is a key area where Java and Kotlin differ in behavior. Java is less strict with nullability syntax.

As an example, the Account class has a few properties, including a String property called name. Java does not have Kotlin’s rules around nullability, instead relying on optional nullability annotations to explicitly declare whether we can assign a null value.

Because the Android framework is written primarily in Java, we might run into this scenario when calling into APIs without nullability annotations.


Platform Types

If we use Kotlin to reference a unannotated name member that is defined in a Java Account class, the compiler doesn’t know whether the String maps to a String or a String? in Kotlin. This ambiguity is represented via a platform typeString!.

String! has no special meaning to the Kotlin compiler. String! can represent either a String or a String?, and the compiler lets us assign a value of either type. Note that we risk throwing a NullPointerException if we represent the type as a String and assign a null value.

To address this issue, we should use nullability annotations whenever we write code in Java. These annotations help both Java and Kotlin developers.

For example, here’s the Account class as it’s defined in Java:

public class Account implements Parcelable {
    public final String name;
    public final String type;
    private final @Nullable String accessId;

    ...
}

One of the member variables, accessId, is annotated with @Nullable, indicating that it can hold a null value. Kotlin would then treat accessId as a String?.

To indicate that a variable can never be null, use the @NonNull annotation:

public class Account implements Parcelable {
    public final @NonNull String name;
    ...
}

In this scenario, name is considered a non-nullable String in Kotlin.

Nullability annotations are included in all new Android APIs and many existing Android APIs. Many Java libraries have added nullability annotations to better support both Kotlin and Java developers.


Handling nullability

If we are unsure about a Java type, we should consider it to be nullable. As an example, the name member of the Account class is not annotated, so we should assume it to be a nullable String.

If we want to trim name so that its value does not include leading or trailing whitespace, we can use Kotlin’s trim function. We can safely trim a String? in a few different ways. One of these ways is to use the not-null assertion operator!!, as shown in the following example:

val account = Account("name", "type")
val accountName = account.name!!.trim()

The !! operator treats everything on its left-hand side as non-null, so in this case, we are treating name as a non-null String. If the result of the expression to its left is null, then our app throws a NullPointerException. This operator is quick and easy, but it should be used sparingly, as it can reintroduce instances of NullPointerException into our code.

A safer choice is to use the safe-call operator?., as shown in the following example:

val account = Account("name", "type")
val accountName = account.name?.trim()

Using the safe-call operator, if name is non-null, then the result of name?.trim() is a name value without leading or trailing whitespace. If name is null, then the result of name?.trim() is null. This means that our app can never throw a NullPointerException when executing this statement.

While the safe-call operator saves us from a potential NullPointerException, it does pass a null value to the next statement. We can instead handle null cases immediately by using an Elvis operator (?:), as shown in the following example:

val account = Account("name", "type")
val accountName = account.name?.trim() ?: "Default name"

If the result of the expression on the left-hand side of the Elvis operator is null, then the value on the right-hand side is assigned to accountName. This technique is useful for providing a default value that would otherwise be null.

We can also use the Elvis operator to return from a function early, as shown in the following example:

fun validateAccount(account: Account?) {
    val accountName = account?.name?.trim() ?: "Default name"

    // account cannot be null beyond this point
    account ?: return

    ...
}


Android API changes

Android APIs are becoming increasingly Kotlin-friendly. Many of Android’s most-common APIs, including AppCompatActivity and Fragment, contain nullability annotations, and certain calls like Fragment#getContext have more Kotlin-friendly alternatives.

For example, accessing the Context of a Fragment is almost always non-null, since most of the calls that we make in a Fragment occur while the Fragment is attached to an Activity (a subclass of Context). That said, Fragment#getContext does not always return a non-null value, as there are scenarios where a Fragment is not attached to an Activity. Thus, the return type of Fragment#getContext is nullable.

Since the Context returned from Fragment#getContext is nullable (and is annotated as @Nullable), we must treat it as a Context? in our Kotlin code. This means applying one of the previously-mentioned operators to address nullability before accessing its properties and functions. For some of these scenarios, Android contains alternative APIs that provide this convenience. Fragment#requireContext, for example, returns a non-null Context and throws an IllegalStateException if called when a Context would be null. This way, we can treat the resulting Context as non-null without the need for safe-call operators or workarounds.


Property Initialization

Properties in Kotlin are not initialized by default. They must be initialized when their enclosing class is initialized.

We can initialize properties in a few different ways. The following example shows how to initialize an index variable by assigning a value to it in the class declaration:

class LoginFragment : Fragment() {
    val index: Int = 12
}

This initialization can also be defined in an initializer block:

class LoginFragment : Fragment() {
    val index: Int

    init {
        index = 12
    }
}

In the examples above, index is initialized when a LoginFragment is constructed.

However, we might have some properties that can’t be initialized during object construction. For example, we might want to reference a View from within a Fragment, which means that the layout must be inflated first. Inflation does not occur when a Fragment is constructed. Instead, it’s inflated when calling Fragment#onCreateView.

One way to address this scenario is to declare the view as nullable and initialize it as soon as possible, as shown in the following example:

class LoginFragment : Fragment() {
    private var statusTextView: TextView? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            statusTextView = view.findViewById(R.id.status_text_view)
            statusTextView?.setText(R.string.auth_failed)
    }
}

While this works as expected, we must now manage the nullability of the View whenever we reference it. A better solution is to use lateinit for View initialization, as shown in the following example:

class LoginFragment : Fragment() {
    private lateinit var statusTextView: TextView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            statusTextView = view.findViewById(R.id.status_text_view)
            statusTextView.setText(R.string.auth_failed)
    }
}

The lateinit keyword allows us to avoid initializing a property when an object is constructed. If our property is referenced before being initialized, Kotlin throws an UninitializedPropertyAccessException, so be sure to initialize our property as soon as possible.

That’s all about in this article.

Related Other Articles / Posts


Conclusion

In this article, We understood about how to apply common Kotlin patterns in Android apps. This article demonstrated the most useful aspects of the Kotlin language like Working with Fragments and Nullability when developing for Android.

Thanks for reading ! I hope you enjoyed and learned about common Kotlin patterns concepts in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – 5 Quick Valuable Concepts To Learn Kotlin Programming Language

Hello Readers, CoolMonkTechie heartily welcomes you in this article (5 Quick Valuable Concepts To Learn Kotlin Programming Language).

In this article, We will learn about Valuable Concepts To Learn Kotlin Programming Language. At Google I/O 2019, Google announced that Android development will be increasingly Kotlin-first, and we’ve stood by that commitment. Kotlin is an expressive and concise programming language that reduces common code errors and easily integrates into existing apps. If we’re looking to build an Android app, we recommend starting with Kotlin to take advantage of its best-in-class features. This article shows the kotlin fundamental for android application development

For understanding the basic fundamental concepts of kotlin, we will explore the below topics one by one:

  • Variable declaration
  • Conditionals
  • Functions
  • Classes
  • Interoperability

A famous quote about learning is :

” Develop a passion for learning. If you do, you will never cease to grow.”

So Let’s begin.


1. Variable declaration

Kotlin uses two different keywords to declare variables: val and var.

  • Use val for a variable whose value never changes. We can’t reassign a value to a variable that was declared using val.
  • Use var for a variable whose value can change.

In the example below, count is a variable of type Int that is assigned an initial value of 10:

var count: Int = 10

Int is a type that represents an integer, one of the many numerical types that can be represented in Kotlin. Similar to other languages, we can also use ByteShortLongFloat, and Double depending on our numerical data.

The var keyword means that we can reassign values to count as needed. For example, we can change the value of count from 10 to 15:

var count: Int = 10
count = 15

Some values are not meant to be changed, though. Consider a String called languageName. If we want to ensure that languageName always holds a value of “Kotlin”, then we can declare languageName using the val keyword:

val languageName: String = "Kotlin"

These keywords allow us to be explicit about what can be changed. Use them to our advantage as needed. If a variable reference must be reassignable, then declare it as a var. Otherwise, use val.


Type inference

Continuing the previous example, when we assign an initial value to languageName, the Kotlin compiler can infer the type based off of the type of the assigned value.

Since the value of "Kotlin" is of type String, the compiler infers that languageName is also a String. Note that Kotlin is a statically-typed language. This means that the type is resolved at compile time and never changes.

In the following example, languageName is inferred as a String, so we can’t call any functions that aren’t part of the String class:

val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()

// Fails to compile
languageName.inc()

toUpperCase() is a function that can only be called on variables of type String. Because the Kotlin compiler has inferred languageName as a String, we can safely call toUpperCase()inc(), however, is an Int operator function, so it can’t be called on a String. Kotlin’s approach to type inference gives us both conciseness and type-safety.


Null safety

In some languages, a reference type variable can be declared without providing an initial explicit value. In these cases, the variables usually contain a null value. Kotlin variables can’t hold null values by default. This means that the following snippet is invalid:

// Fails to compile
val languageName: String = null

For a variable to hold a null value, it must be of a nullable type. We can specify a variable as being nullable by suffixing its type with ?, as shown in the following example:

val languageName: String? = null

With a String? type, we can assign either a String value or null to languageName.

We must handle nullable variables carefully or risk a dreaded NullPointerException. In Java, for example, if we attempt to invoke a method on a null value, our program crashes.

Kotlin provides a number of mechanisms for safely working with nullable variables.


2. Conditionals

Kotlin features several mechanisms for implementing conditional logic. The most common of these is an if-else statement. If an expression wrapped in parentheses next to an if keyword evaluates to true, then code within that branch (i.e. the immediately-following code that is wrapped in curly braces) is executed. Otherwise, the code within the else branch is executed.

Example : if / else

if (count == 42) {
    println("I have the answer.")
} else {
    println("The answer eludes me.")
}

We can represent multiple conditions using else if. This lets us represent more granular, complex logic within a single conditional statement, as shown in the following example:

if (count == 42) {
    println("I have the answer.")
} else if (count > 35) {
    println("The answer is close.")
} else {
    println("The answer eludes me.")
}

Conditional Expressions

Conditional statements are useful for representing stateful logic, but we may find that we repeat ourself when writing them. In the example above, we simply print a String in each branch. To avoid this repetition, Kotlin offers conditional expressions. The last example can be rewritten as follows:

val answerString: String = if (count == 42) {
    "I have the answer."
} else if (count > 35) {
    "The answer is close."
} else {
    "The answer eludes me."
}

println(answerString)

Implicitly, each conditional branch returns the result of the expression on its final line, so we don’t need to use a return keyword. Because the result of all three branches is of type String, the result of the if-else expression is also of type String. In this example, answerString is assigned an initial value from the result of the if-else expression. Type inference can be used to omit the explicit type declaration for answerString, but it’s often a good idea to include it for clarity.

We aware that Kotlin does not include a traditional ternary operator, instead favoring the use of conditional expressions.

As the complexity of our conditional statement grows, we might consider replacing our if-else expression with a when expression, as shown in the following example:

val answerString = when {
    count == 42 -> "I have the answer."
    count > 35 -> "The answer is close."
    else -> "The answer eludes me."
}

println(answerString)

Each branch in a when expression is represented by a condition, an arrow (->), and a result. If the condition on the left-hand side of the arrow evaluates to true, then the result of the expression on the right-hand side is returned. Note that execution does not fall through from one branch to the next. The code in the when expression example is functionally-equivalent to that in the previous example but is arguably easier to read.

Smart Casting

Kotlin’s conditionals highlight one of its more powerful features, smart casting. Rather than using the safe-call operator or the not-null assertion operator to work with nullable values, we can instead check if a variable contains a reference to a null value using a conditional statement, as shown in the following example:

val languageName: String? = null
if (languageName != null) {
    // No need to write languageName?.toUpperCase()
    println(languageName.toUpperCase())
}

Within the conditional branch, languageName may be treated as non-nullable. Kotlin is smart enough to recognize that the condition for executing the branch is that languageName does not hold a null value, so we do not have to treat languageName as nullable within that branch. This smart casting works for null checkstype checks, or any condition that satisfies a contract.


3. Functions

We can group one or more expressions into a function. Rather than repeating the same series of expressions each time that we need a result, we can wrap the expressions in a function and call that function instead.

To declare a function, use the fun keyword followed by the function name. Next, define the types of inputs that our function takes, if any, and declare the type of output that it returns. A function’s body is where we define expressions that are called when our function is invoked.

Building on previous examples, here’s a complete Kotlin function:

fun generateAnswerString(): String {
    val answerString = if (count == 42) {
        "I have the answer."
    } else {
        "The answer eludes me"
    }

    return answerString
}

The function in the example above has the name generateAnswerString. It doesn’t take any input. It outputs a result of type String. To call a function, use its name, followed by the invocation operator (()). In the example below, the answerString variable is initialized with the result from generateAnswerString().

val answerString = generateAnswerString()

Functions can take arguments as input, as shown in the following example:

fun generateAnswerString(countThreshold: Int): String {
    val answerString = if (count > countThreshold) {
        "I have the answer."
    } else {
        "The answer eludes me."
    }

    return answerString
}

When declaring a function, we can specify any number of arguments and their types. In the example above, generateAnswerString() takes one argument named countThreshold of type Int. Within the function, we can refer to the argument by using its name.

When calling this function, we must include an argument within the function call’s parentheses:

val answerString = generateAnswerString(42)


Simplifying function declarations

generateAnswerString() is a fairly simple function. The function declares a variable and then immediately returns. When the result of a single expression is returned from a function, we can skip declaring a local variable by directly returning the result of the if-else expression contained in the function, as shown in the following example:

fun generateAnswerString(countThreshold: Int): String {
    return if (count > countThreshold) {
        "I have the answer."
    } else {
        "The answer eludes me."
    }
}

We can also replace the return keyword with the assignment operator:

fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
        "I have the answer"
    } else {
        "The answer eludes me"
    }


Anonymous functions

Not every function needs a name. Some functions are more directly identified by their inputs and outputs. These functions are called anonymous functions. We can keep a reference to an anonymous function, using this reference to call the anonymous function later. We can also pass the reference around our application, as with other reference types.

val stringLengthFunc: (String) -> Int = { input ->
    input.length
}

Like named functions, anonymous functions can contain any number of expressions. The returned value of the function is the result of the final expression.

In the example above, stringLengthFunc contains a reference to an anonymous function that takes a String as input and returns the length of the input String as output of type Int. For that reason, the function’s type is denoted as (String) -> Int. This code does not invoke the function, however. To retrieve the result of the function, we must invoke it with like we would a named function. We must supply a String when calling stringLengthFunc, as shown in the following example:

val stringLengthFunc: (String) -> Int = { input ->
    input.length
}

val stringLength: Int = stringLengthFunc("Android")


Higher-order functions

A function can take another function as an argument. Functions that use other functions as arguments are called Higher-order functions. This pattern is useful for communicating between components in the same way that we might use a callback interface in Java.

Here’s an example of a higher-order function:

fun stringMapper(str: String, mapper: (String) -> Int): Int {
    // Invoke function
    return mapper(str)
}

The stringMapper() function takes a String along with a function that derives an Int value from a String that we pass into it.

We can call stringMapper() by passing a String and a function that satisfies the other input parameter, namely a function that takes a String as input and outputs an Int, as shown in the following example:

stringMapper("Android", { input ->
    input.length
})

If the anonymous function is the last parameter defined on a function, we can pass it outside of the parentheses used to invoke the function, as shown in the following example:

stringMapper("Android") { input ->
    input.length
}

Anonymous functions can be found throughout the Kotlin standard library. 


4. Classes

All of the types mentioned so far are built into the Kotlin programming language. If we would like to add our own custom type, we can define a class using the class keyword, as shown in the following example:

class Car


Properties

Classes represent state using properties. A property is a class-level variable that can include a getter, a setter, and a backing field.

Since a car needs wheels to drive, we can add a list of Wheel objects as a property of Car, as shown in the following example:

class Car {
    val wheels = listOf<Wheel>()
}

Note that wheels is a public val, meaning that wheels can be accessed from outside of the Car class, and it can’t be reassigned. If we want to obtain an instance of Car, we must first call its constructor. From there, we can access any of its accessible properties.

val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car

If we want to customize our wheels, we can define a custom constructor that specifies how our class properties are initialized:

class Car(val wheels: List<Wheel>)

In the example above, the class constructor takes a List<Wheel> as a constructor argument and uses that argument to initialize its wheels property.


Class functions and encapsulation

Classes use functions to model behavior. Functions can modify state, helping us to expose only the data that we wish to expose. This access control is part of a larger object-oriented concept known as encapsulation.

In the following example, the doorLock property is kept private from anything outside of the Car class. To unlock the car, we must call the unlockDoor() function passing in a valid key, as shown in the following example:

class Car(val wheels: List<Wheel>) {

    private val doorLock: DoorLock = ...

    fun unlockDoor(key: Key): Boolean {
        // Return true if key is valid for door lock, false otherwise
    }
}

If we would like to customize how a property is referenced, we can provide a custom getter and setter. For example, if we would like to expose a property’s getter while restricting access to its setter, we can designate that setter as private:

class Car(val wheels: List<Wheel>) {

    private val doorLock: DoorLock = ...

    var gallonsOfFuelInTank: Int = 15
        private set

    fun unlockDoor(key: Key): Boolean {
        // Return true if key is valid for door lock, false otherwise
    }
}

With a combination of properties and functions, we can create classes that model all types of objects.


5. Interoperability

One of Kotlin’s most important features is its fluid interoperability with Java. Because Kotlin code compiles down to JVM bytecode, our Kotlin code can call directly into Java code and vice-versa. This means that we can leverage existing Java libraries directly from Kotlin. Furthermore, the majority of Android APIs are written in Java, and we can call them directly from Kotlin.

That’s all about in this article.


Conclusion

In this article, We understood about Valuable Concepts To Learn Kotlin Programming Language. Kotlin is a flexible, pragmatic language with growing support and momentum. We discussed about Kotlin fundamental like variable declaration, function, conditions and classes concepts which is widely used by Android developers everywhere for application development. This article showed the basic Kotlin fundamental concepts for android application development

Thanks for reading ! I hope you enjoyed and learned about the basic fundamental concepts of Kotlin for android development. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

React Native – How To Handle Deep Linking in React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Handle Deep Linking in React Native ?).

In this article, We will learn how to handle deep linking in react native. Mobile apps have a unique vulnerability that is non-existent in the web: Deep Linking. Deep Linking is a technique in which a given URL or resource is used to open a specific page or screen on mobile. So, instead of just launching the app on mobile, a deep link can lead a user to a specific page within the app, providing a better experience. This specific page or screen may reside under a series of hierarchical pages, hence the term “deep” in deep linking.

Deep linking is a way of sending data directly to a native application from an outside source. A deep link looks like app:// where app is our app scheme and anything following the // could be used internally to handle the request. As a user, we probably have experienced deep linking when opening a link to a product in a browser. If we have the app of that shop installed, it may use a deep link to open the app on that product’s page.

For example, if we were building an e-commerce app, we could use app://products/1 to deep link to our app and open the product detail page for a product with id 1. We can think of these kind of like URLs on the web.

Deep linking consists of using a uniform resource identifier (URI) that links to a specific location within a mobile app rather than simply launching the app. Deferred deep linking allows users to deep link to content even if the app is not already installed.

In this article, we will discuss a React Native app that opens a specific page based on the URI provided from an external source.

A famous quote about learning is :

” The beautiful thing about learning is nobody can take it away from you. “

So Let’s begin.


Why Deep Linking?

Deep Link has many use cases where it can come very handy. Think of marketing strategies, referral links, sharing a certain product, etc. The greatest benefit of mobile deep linking is the ability for marketers and app developers to bring users directly into the specific location within their app with a dedicated link. Just as deep links made the web more usable, mobile deep links do the same for mobile apps.


Example

Let’s try to mimic a React Native demo app that opens a specific page based on the URI provided from an external source. To handle deep links, we are going to use an optimum solution provided by the react-navigation library.


Configure react-navigation in a React Native App

To start, we create a new React Native project by running the following command:

react-native init rnDeepLinkingDemo

cd rnDeepLinkingDemo

To be able to support deep linking via the navigation, we add the required npm dependencies. Once the project directory has been generated from the above command, navigate inside the project folder from our terminal and install the following dependencies.

npm install react-navigation --save

npm install react-native-gesture-handler react-native-safe-area-context @react-native-community/masked-view react-native-screens react-native-reanimated --save

npm install react-navigation-stack --save

The next step is to link all the libraries we just installed. From React Native 0.60 and higher, linking is automatic. So we don’t need to run react-native link.

On iOS devices, we just have to run the following set of commands.

cd ios
pod install
cd ..

For Android devices, we add the following lines to the android/app/build.gradle file under the dependencies section:

implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'

Then, open the android/app/src/main/java/com/rndeeplinkdemo/MainActivity.java file and add the following snippet:

package com.rndeeplinkingdemo;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
  @Override
  protected String getMainComponentName() {
    return "RNDeepLinkingDemo";
  }

  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
        @Override
        protected ReactRootView createRootView() {
            return new RNGestureHandlerEnabledRootView(MainActivity.this);
        }
    };
  }

}


Create a Home & Details Screen

We are going to create all the screens for this example inside the directory src/screens. To start with the home screen, create a new file Home.js inside the aforementioned path.

This screen is going to render a list of users from an array of mock data from a placeholder API using a FlatList component. Each user is going to be wrapped inside a TouchableOpacity. The reason being, when an end-user presses a username from the list, this is going to contain the logic for navigating from the Home screen to the Details screen (which we will add later).

import React, {useState, useEffect} from 'react';
import {View, Text, FlatList, TouchableOpacity} from 'react-native';

function Home({navigation}) {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((res) => res.json())
      .then((res) => {
        setData(res);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  const Separator = () => (
    <View
      style={{
        borderBottomColor: '#d3d3d3',
        borderBottomWidth: 1,
        marginTop: 10,
        marginBottom: 10,
      }}
    />
  );
  return (
    <View style={{flex: 1}}>
      <View style={{paddingHorizontal: 20, paddingVertical: 20}}>
        <FlatList
          data={data}
          keyExtractor={(item) => item.id.toString()}
          ItemSeparatorComponent={Separator}
          renderItem={({item}) => (
            <TouchableOpacity
              onPress={() => navigation.navigate('Details', {item})}>
              <Text style={{fontSize: 24}}>{item.name}</Text>
            </TouchableOpacity>
          )}
        />
      </View>
    </View>
  );
}
export default Home;

For the details screen, for now, let us display user list details. We create a new file called Details.js. To display information for each user when visiting the Details screen, we have to pass the value of each item using navigation parameters. Next, To fetch the data from the placeholder API on initial render, let us use the useEffect hook from React. This hook is going to behave like a good old lifecycle method componentDidMount(). It also allows that if the full item object is passed or not. If not, just grab the userId and request the API. Then, define a state variable data to store the incoming user information. Also, modify the contents of return in this component screen.

import React, {useState, useEffect} from 'react';
import {View, Text} from 'react-native';

function Details({navigation}) {
  const [data, setData] = useState([]);

  useEffect(() => {
    const item = navigation.getParam('item', {});

    if (Object.keys(item).length === 0) {
      const userId = navigation.getParam('userId', 1);
      fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
        .then((res) => res.json())
        .then((res) => {
          const data = [];

          Object.keys(res).forEach((key) => {
            data.push({key, value: `${res[key]}`});
          });

          setData(data);
        });
    } else {
      const data = [];

      Object.keys(item).forEach((key) => {
        data.push({key, value: `${item[key]}`});
      });

      setData(data);
    }
  }, []);

  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      {data.map((data) => (
        <Text
          style={{fontSize: 20}}
          key={data.key}>{`${data.key}: ${data.value}`}</Text>
      ))}
    </View>
  );
}

export default Details;


Configure Deep Linking in React Navigation

To navigate from Home to Details screen, we need Stack Navigator from react-navigation. We create a new file called index.js inside the src/navigation directory and import the following statements.

import React from 'react'
import { createAppContainer, createSwitchNavigator } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import Home from '../screens/Home'
import Details from '../screens/Details'

Create a stack navigator with Home as the initial screen. To enable deep linking, the current app requires an identifier to recognize the URI path from the external source to the screen of the app. The library react-navigation provides a path attribute for this. It tells the router relative path to match against the URL. We configure both the routes as follows:

const MainApp = createStackNavigator({
  Home: {
    screen: Home,
    navigationOptions: {
      headerTitle: 'Home',
    },
    path: 'home',
  },
  Details: {
    screen: Details,
    navigationOptions: {
      headerTitle: 'Details',
    },
    path: 'details/:userId',
  },
});

In the above snippet, the dynamic variable specified by :userId is passed to details/. This is going to allow the app to accept a dynamic value such as details/1234.

Next, we add the configuration to the navigation to extract the path from the incoming URL from the external resource. This is done by uriPrefix. Add the following code snippet at the end of the file:

export default () => {
  const prefix = 'myapp://';
  return <AppContainer uriPrefix={prefix} />;
};

The full code of index.js file is as below :

import React from 'react';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import Home from '../screens/Home';
import Details from '../screens/Details';

const MainApp = createStackNavigator({
  Home: {
    screen: Home,
    navigationOptions: {
      headerTitle: 'Home',
    },
    path: 'home',
  },
  Details: {
    screen: Details,
    navigationOptions: {
      headerTitle: 'Details',
    },
    path: 'details/:userId',
  },
});

const AppContainer = createAppContainer(MainApp);

export default () => {
  const prefix = 'myapp://';
  return <AppContainer uriPrefix={prefix} />;
};

Import this navigation module inside the App.js file for it to work:

import React from 'react';
import AppContainer from './src/navigation';

const App = () => {
  return <AppContainer />;
};

export default App;


Configure URI Scheme For Native iOS Apps

To make this work, we have to configure the native iOS and Android app to open URLs based on the prefix myapp://.

For iOS devices, open the ios/rnDeepLinkDemo/AppDelegate.m file and add the following.

// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this above the `@end`:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
 options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
 return [RCTLinkingManager application:app openURL:url options:options];
}

Open ios/rnDeepLinkingDemo.xcodeproj in the Xcode app and select the app from the left navigation bar.

Open the Info tab.

Next, go to the URL Types.

Click the + button and in identifier as well as URL schemes add myapp.

Rebuild the React Native binaries by running react-native run-ios.

For Android users, we have to configure the external linking as well. Open /android/app/src/main/AndroidManifest.xml and set the value of launchMode to singleTask. Also, add a new intent-filter:

<activity
 android:name=".MainActivity"
 <!--set the below value-->
 android:launchMode="singleTask">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 <!--Add the following-->

 <intent-filter>
 <action android:name="android.intent.action.VIEW" />
 <category android:name="android.intent.category.DEFAULT" />
 <category android:name="android.intent.category.BROWSABLE" />
 <data android:scheme="myapp" />
 </intent-filter>
</activity>

Let’s understand the intent-filter a little better.

An intent filter is an expression in an app’s manifest file that specifies the type of intents that the component would like to receive.

Get a closer look on <data> tag inside <intent-filter>. There are two properties that we have to care about. Consider scheme as a type of incoming link and host as the URL.

Our Deep Link will look something like this: myapp://home .


Testing The App

Before we run the app on our platform of choice, make sure to re-build it using the specific command for the mobile OS as below:

# ios
react-native run-ios

# android
react-native run-android

The Example app output is going to be like below.

To test deep link in iOS, we open a web browser in our iOS simulator device and run the URL myapp://home. It is going to ask us to whether open the external URI in the app . Next, try entering the URL myapp://details/1 and see what happens.

To test deep link in Android, we make sure our android app is in background and run this command:

adb shell am start -W -a android.intent.action.VIEW -d myapp://home com.rndeeplinkingdemo

adb shell am start -W -a android.intent.action.VIEW -d myapp://details/1 com.rndeeplinkingdemo

If our package has a different name then edit command as follows:

$ adb shell am start -W -a android.intent.action.VIEW -d <URI> <PACKAGE>

If our App opened successfully then our Deep Linking is working as expected.

That’s all about in this article.


Conclusion

In this article, We understood how to handle Deep Linking in React Native. We also discussed about a complete demo of a React Native app that handles deep linking using react-navigation. Deep linking can bring significant improvements to the user experience of our mobile apps and enable search engines to provide context-sensitive searches and results.

Thanks for reading ! I hope you enjoyed and learned about the Deep Linking Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

React Native Official Website

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – How To Manage The Lifecycle of Gestures In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Manage The Lifecycle of Gestures In React Native ?).

In this article, We will learn how to manage the lifecycle of gestures in react native. The gesture responder system manages the lifecycle of gestures in react native application. A touch can go through several phases as the app determines what the user’s intention is. For example, the app needs to determine if the touch is scrolling, sliding on a widget, or tapping. This can even change during the duration of a touch. There can also be multiple simultaneous touches.

The touch responder system is needed to allow components to negotiate these touch interactions without any additional knowledge about their parent or child components.

A famous quote about learning is :

” Change is the end result of all true learning. “

So Let’s begin.


Best Practices

To make our app feel great, every action should have the following attributes:

  • Feedback/highlighting – show the user what is handling their touch, and what will happen when they release the gesture
  • Cancel-ability – when making an action, the user should be able to abort it mid-touch by dragging their finger away

These features make users more comfortable while using an app, because it allows people to experiment and interact without fear of making mistakes.


TouchableHighlight and Touchable

The responder system can be complicated to use. So we have provided an abstract Touchable implementation for things that should be “tappable“. This uses the responder system and allows us to configure tap interactions declaratively. Use TouchableHighlight anywhere where we would use a button or link on web.


Gesture Responder System Lifecycle

A view can become the touch responder by implementing the correct negotiation methods. There are two methods to ask the view if it wants to become responder:

  • View.props.onStartShouldSetResponder: (evt) => true, – Does this view want to become responder on the start of a touch?
  • View.props.onMoveShouldSetResponder: (evt) => true, – Called for every touch move on the View when it is not the responder: does this view want to “claim” touch responsiveness?

If the View returns true and attempts to become the responder, one of the following will happen:

  • View.props.onResponderGrant: (evt) => {} – The View is now responding for touch events. This is the time to highlight and show the user what is happening.
  • View.props.onResponderReject: (evt) => {} – Something else is the responder right now and will not release it.

If the view is responding, the following handlers can be called:

  • View.props.onResponderMove: (evt) => {} – The user is moving their finger.
  • View.props.onResponderRelease: (evt) => {} – Fired at the end of the touch, ie “touchUp”.
  • View.props.onResponderTerminationRequest: (evt) => true – Something else wants to become responder. Should this view release the responder? Returning true allows release.
  • View.props.onResponderTerminate: (evt) => {} – The responder has been taken from the View. Might be taken by other views after a call to onResponderTerminationRequest, or might be taken by the OS without asking (happens with control center/ notification center on iOS).

evt is a synthetic touch event with the following nativeEvent form:

  • changedTouches – Array of all touch events that have changed since the last event
  • identifier – The ID of the touch
  • locationX – The X position of the touch, relative to the element
  • locationY – The Y position of the touch, relative to the element
  • pageX – The X position of the touch, relative to the root element
  • pageY – The Y position of the touch, relative to the root element
  • target – The node id of the element receiving the touch event
  • timestamp – A time identifier for the touch, useful for velocity calculation
  • touches – Array of all current touches on the screen


Capture ShouldSet Handlers

onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, where the deepest node is called first. That means that the deepest component will become responder when multiple Views return true for ShouldSetResponder handlers. This is desirable in most cases, because it makes sure all controls and buttons are usable.

However, sometimes a parent will want to make sure that it becomes responder. This can be handled by using the capture phase. Before the responder system bubbles up from the deepest component, it will do a capture phase, firing on ShouldSetResponderCapture. So if a parent View wants to prevent the child from becoming responder on a touch start, it should have a onStartShouldSetResponderCapture handler which returns true.

  • View.props.onStartShouldSetResponderCapture: (evt) => true,
  • View.props.onMoveShouldSetResponderCapture: (evt) => true,


Pan Responder

PanResponder reconciles several touches into a single gesture. It makes single-touch gestures resilient to extra touches, and can be used to recognize basic multi-touch gestures.

By default, PanResponder holds an InteractionManager handle to block long-running JS events from interrupting active gestures.

It provides a predictable wrapper of the responder handlers provided by the gesture responder system. For each handler, it provides a new gestureState object alongside the native event object:

onPanResponderMove: (event, gestureState) => {}

A native event is a synthetic touch event with form of PressEvent.

gestureState object has the following:

  • stateID – ID of the gestureState- persisted as long as there at least one touch on screen
  • moveX – the latest screen coordinates of the recently-moved touch
  • moveY – the latest screen coordinates of the recently-moved touch
  • x0 – the screen coordinates of the responder grant
  • y0 – the screen coordinates of the responder grant
  • dx – accumulated distance of the gesture since the touch started
  • dy – accumulated distance of the gesture since the touch started
  • vx – current velocity of the gesture
  • vy – current velocity of the gesture
  • numberActiveTouches – Number of touches currently on screen


API

Only a single component can respond to touch events at one time – the component responding to events owns a global “interaction lock”. The PanResponder API helps us manage what component owns this lock through a set of callbacks. Each of these callbacks is also passed an event and gestureState object containing info about the touch events (e.g. position and velocity).

To create a PanResponder, we call PanResponder.create(callbacksObject). The result is a set of props that can be passed to View as props (these are the lower-level touch event handling props). We’ll typically wrap the result with useRef, since we only want to create a single PanResponder for the lifecycle of the component.

The full set of callbacks we can pass is:

  • onStartShouldSetPanResponder: (event, gestureState) => {}
  • onStartShouldSetPanResponderCapture: (event, gestureState) => {}
  • onMoveShouldSetPanResponder: (event, gestureState) => {}
  • onMoveShouldSetPanResponderCapture: (event, gestureState) => {}
  • onPanResponderReject: (event, gestureState) => {}
  • onPanResponderGrant: (event, gestureState) => {}
  • onPanResponderStart: (event, gestureState) => {}
  • onPanResponderEnd: (event, gestureState) => {}
  • onPanResponderRelease: (event, gestureState) => {}
  • onPanResponderMove: (event, gestureState) => {}
  • onPanResponderTerminate: (event, gestureState) => {}
  • onPanResponderTerminationRequest: (event, gestureState) => {}
  • onShouldBlockNativeResponder: (event, gestureState) => {}


Usage Pattern

const ExampleComponent = () => {
  const panResponder = React.useRef(
    PanResponder.create({
      // Ask to be the responder:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) =>
        true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) =>
        true,

      onPanResponderGrant: (evt, gestureState) => {
        // The gesture has started. Show visual feedback so the user knows
        // what is happening!
        // gestureState.d{x,y} will be set to zero now
      },
      onPanResponderMove: (evt, gestureState) => {
        // The most recent move distance is gestureState.move{X,Y}
        // The accumulated gesture distance since becoming responder is
        // gestureState.d{x,y}
      },
      onPanResponderTerminationRequest: (evt, gestureState) =>
        true,
      onPanResponderRelease: (evt, gestureState) => {
        // The user has released all touches while this view is the
        // responder. This typically means a gesture has succeeded
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // Another component has become the responder, so this gesture
        // should be cancelled
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // Returns whether this component should block native components from becoming the JS
        // responder. Returns true by default. Is currently only supported on android.
        return true;
      }
    })
  ).current;

  return <View {...panResponder.panHandlers} />;
};


Example

PanResponder works with Animated API to help build complex gestures in the UI. The following example contains an animated View component which can be dragged freely across the screen.

import React, { useRef } from "react";
import { Animated, View, StyleSheet, PanResponder, Text } from "react-native";

const App = () => {
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        pan.setOffset({
          x: pan.x._value,
          y: pan.y._value
        });
      },
      onPanResponderMove: Animated.event(
        [
          null,
          { dx: pan.x, dy: pan.y }
        ]
      ),
      onPanResponderRelease: () => {
        pan.flattenOffset();
      }
    })
  ).current;

  return (
    <View style={styles.container}>
      <Text style={styles.titleText}>Drag this box!</Text>
      <Animated.View
        style={{
          transform: [{ translateX: pan.x }, { translateY: pan.y }]
        }}
        {...panResponder.panHandlers}
      >
        <View style={styles.box} />
      </Animated.View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  },
  titleText: {
    fontSize: 14,
    lineHeight: 24,
    fontWeight: "bold"
  },
  box: {
    height: 150,
    width: 150,
    backgroundColor: "blue",
    borderRadius: 5
  }
});

export default App;

The output of the above example is :

That’s all about in this article.


Conclusion

In this article, We understood how to manage the lifecycle of gestures in react native. We also discussed about Best Practices and PanResponser usage in React Native platform.

Thanks for reading ! I hope you enjoyed and learned about the Gestures Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

React Native Official Website

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – How To Navigate Between Screens In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Navigate Between Screens In React Native ?).

In this article, We will learn how to navigate between screens in react native. Mobile apps are rarely made up of a single screen. Managing the presentation of, and transition between, multiple screens is typically handled by what is known as a navigator. This article covers the various navigation components available in React Native. If we are getting started with navigation, we will probably want to use React Navigation. React Navigation provides a straightforward navigation solution, with the ability to present common stack navigation and tabbed navigation patterns on both Android and iOS.

If we’d like to achieve a native look and feel on both Android and iOS, or we’re integrating React Native into an app that already manages navigation natively, the following library provides native navigation on both platforms: react-native-navigation.

A famous quote about learning is :

” Study hard what interests you the most in the most undisciplined, irreverent and original manner possible. “

So Let’s begin.


Overview

The community solution to navigation is a standalone library that allows developers to set up the screens of an app with a few lines of code.

React Navigation is the most popular navigation library. It handles most of the challenges described above nicely, and is sufficiently configurable for most apps.

React Navigation provides all the different type of navigator like

  • Stack Navigator : For the simple screen switching
  • Drawer Navigator : To create Navigation Drawer/ Sidebar
  • Bottom Tab Navigator : For the bottom navigation
  • Top Tab Navigator : To create the tab navigation


Navigation Challenges

There are a few aspects of navigation which make it challenging in React Native:

  • Navigation works differently on each native platform. iOS uses view controllers, while android uses activities. These platform-specific APIs work differently technically and appear differently to the user. React Native navigation libraries try to support the look-and-feel of each platform, while still providing a single consistent JavaScript API.
  • Native navigation APIs don’t correspond with “views”. React Native components like ViewText, and Image, roughly map to an underlying native “view”, but there isn’t really an equivalent for some of the navigation APIs. There isn’t always a clear way to expose these APIs to JavaScript.
  • Navigation on mobile is stateful. On the web, navigation is typically stateless, where a url (i.e. route) takes a user to a single screen/page. On mobile, the history of the user’s navigation state is persisted in the application so that the user can go back to previous screens – a stack of screens can even include the same screen multiple times.

Due to these challenges, there isn’t a single best way to implement navigation, so it was removed from the core React Native package.


Installation and Setup

First, we need to install them in our project:

npm install @react-navigation/native @react-navigation/stack

Next, we install the required peer dependencies. We need to run different commands depending on whether our project is an Expo managed project or a bare React Native project.

  • If we have an Expo managed project, install the dependencies with expo:
expo install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
  • If we have a bare React Native project, install the dependencies with npm:
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

For iOS with bare React Native project, make sure we have Cocoapods installed. Then we install the pods to complete the installation:

cd ios
pod install
cd ..

We might get warnings related to peer dependencies after installation. They are usually caused by incorrect version ranges specified in some packages. We can safely ignore most warnings as long as our app builds.

To finalize installation of react-native-gesture-handler, add the following at the top (make sure it’s at the top and there’s nothing else before it) of our entry file, such as index.js or App.js:

import 'react-native-gesture-handler';

Now, we need to wrap the whole app in NavigationContainer. Usually we’d do this in our entry file, such as index.js or App.js :

import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

const App = () => {
  return (
    <NavigationContainer>
      {/* Rest of app code */}
    </NavigationContainer>
  );
};

export default App;

Now we are ready to build and run our app on the device/simulator.


Steps For Adding React Navigation To The App

In this section, we’ll walk through adding react-navigation to an app.

After install the required dependencies, we need to do 3 things:

  • Set up a <NavigationContainer> from @react-navigation/native
  • Create a navigator:
    • createStackNavigator from @react-navigation/stack
    • createBottomTabNavigator from @react-navigation/bottom-tabs
    • createDrawerNavigator from @react-navigation/drawer
  • Define the screens in our app


1. Create a navigator

We first choose one of the available navigators, e.g. stack, which will act as our root navigator. Navigators may be nested later.

import { createStackNavigator } from '@react-navigation/stack'

const Root = createStackNavigator()


2. Create screen components

Next, we create a component for each screen.

Screens are regular React components. They’ll be passed navigation-specific props when instantiated.

const Screen1 = ({ navigation, route }) => {
  return <Text>Screen1</Text>
}


3. Render it

Lastly, we render a NavigationContainer with our navigator within it.

Each Screen component defines a route in our app. If we want nested navigators, e.g. a tab navigator within a stack navigator, we can use another navigator as a screen’s component. We only need a single NavigationContainer, even if we have nested navigators.

import { NavigationContainer } from '@react-navigation/native'

// ...

const App = () => {
  return (
    <NavigationContainer>
      <Root.Navigator>
        <Root.Screen name="Screen1" component={Screen1} />
        <Root.Screen name="Screen2" component={Screen2} />
        <Root.Screen name="Screen3" component={Screen3} />
      </Root.Navigator>
    </NavigationContainer>
  )
}


Navigating and Routes

Each navigator supports different ways of navigating:

  • Stack: push
  • Tabs: navigate
  • Drawer: openDrawer

When navigating, we typically specify a screen name and optionally parameters, e.g. navigator.push("Screen2", { paramA: "Hello!" }).


Navigation

In this example, we navigate from Screen1 to Screen2 by pushing Screen2 onto the stack when a button is pressed.

const Screen1 = ({ navigation }) => {
  return (
    <Button
      onPress={() => {
        navigation.push('Screen2', { paramA: 'Hello!' })
      }}
    />
  )
}


Routes

Within a screen, we have access to the current route and it’s parameters.

const Screen2 = ({ route }) => {
  return <Text>{route.params.paramA}</Text>
}


Hooks

For components which aren’t screens (direct descendants of a navigator), we can access the navigation and route objects using hooks. Some developers prefer using these hooks instead of props, even in screen components.

import { useNavigation, useRoute } from '@react-navigation/native'

const Screen1 = () => {
  const navigation = useNavigation()
  const route = useRoute()

  // ...
}


Usage

Now we can create an app with a home screen and a profile screen:

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

const MyStack = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          name="Home"
          component={HomeScreen}
          options={{ title: 'Welcome' }}
        />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

In this example, there are 2 screens (Home and Profile) defined using the Stack.Screen component. Similarly, we can define as many screens as we like.

We can set options such as the screen title for each screen in the options prop of Stack.Screen.

Each screen takes a component prop that is a React component. Those components receive a prop called navigation which has various methods to link to other screens. For example, we can use navigation.navigate to go to the Profile screen:

const HomeScreen = ({ navigation }) => {
  return (
    <Button
      title="Go to Jane's profile"
      onPress={() =>
        navigation.navigate('Profile', { name: 'Jane' })
      }
    />
  );
};
const ProfileScreen = () => {
  return <Text>This is Jane's profile</Text>;
};

The views in the stack navigator use native components and the Animated library to deliver 60fps animations that are run on the native thread. Plus, the animations and gestures can be customized.

React Navigation also has packages for different kind of navigators such as tabs and drawer. We can use them to implement various patterns in our app.

That’s all about in this article.


Conclusion

In this article, We understood how to navigate between screens in react native. We also discussed about navigation challenges, dependencies and navigation usage in React Native platform.

Thanks for reading ! I hope you enjoyed and learned about the Navigation Concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of React Native as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

Exit mobile version