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!!???

React Native – How To Use Hooks In React Native ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Use Hooks In React Native ?).

In this article, we will understand about how to use Hooks in react native. Hooks are specially-implemented functions that let us add functionality to React components beyond just creating and returning React elements. This article demonstrates the built-in hooks usage in react native application.

A famous quote about learning is :

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

So Let’s begin.


React Hooks

” React Hooks are a new addition in React 16.8 that let you use state and other React features without writing a class component. In other words, Hooks are functions that let you “hook into” React state and lifecycle features from function components. (They do not work inside class components.)”

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. It mainly uses to handle the state and side effects in react functional component. React Hooks are a way to use stateful functions inside a functional component. Hooks don’t work inside classes — they let you use React without classesReact provides a few built-in Hooks like useState and useEffect. The React hooks do :

  • Best practices
  • Easy to under understand
  • Easy to test
  • Increases the performance and so on.


Rules and Linting

Hooks aren’t regular functions; they have to be written in a certain way. To dive deeper into this topic, check out:

ReactJS – How to Effectively Think In React Hooks ?

When using hooks, we typically want to use eslint and the react-hooks plugin. Hooks are powerful, but can be unintuitive at first, and this tool catches a lot of mistakes before we ever run our code.


In-built React Hooks APIs

We’ll look at the following built-in hooks in more detail:

  • useState – Persist state within a component function
  • useReducer – Similar to useState, but for state that involves multiple sub-values
  • useEffect – Perform side effects within our component functions
  • useRef – Wrap a mutable value


1. useState

The useState hook lets us “remember” a value within a component function. Since our component function may be called many times throughout the lifecycle of the component, any variable we declare normally (i.e. with let myVar = ...) will get reset. With useState, React can remember a state variable for us, making sure it gets passed into our component instance correctly.


API

The useState hook takes a single argument, our initial state, and returns an array containing two elements:

  • state – the current state
  • setState – a function to update our state

Syntax –  const [state, setState] = useState(initialValue)


Example

In this example, we’ll use useState to append to an array.

The useState hook can store any type of value: a number, a string, an array, an object, etc.

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

const randomDiceRoll = () => Math.floor(Math.random() * 6) + 1

export default function App() {
  const [diceRolls, setDiceRolls] = useState([])

  return (
    <View>
      <Button
        title="Roll dice!"
        onPress={() => {
          setDiceRolls([...diceRolls, randomDiceRoll()])
        }}
      />
      {diceRolls.map((diceRoll, index) => (
        <Text style={{ fontSize: 24 }} key={index}>
          {diceRoll}
        </Text>
      ))}
    </View>
  )
}

The result of above example is displayed below :


Updating mutable state values

Note how when we call setDiceRoll, we’re not pushing the integer returned from randomDiceRoll() into the diceRolls array. Instead, we return a new array containing the destructured diceRolls array and the newly randomized dice roll. Why?

Hooks can tell React to re-run our component function and update the UI. The useState hook tells React to re-run our component function whenever we call setDiceRolls with a different value. Internally, useState then compares the current value of diceRolls with the value we passed to setDiceRolls using ===. If we’re using a mutable value like an array, and we only change its contents, useState won’t detect that change and won’t tell React to re-run our component function. This will result in our UI displaying old/stale data. To avoid this problem we need to create a new array, so that useState will detect that our data changed and display the newest data.


2. useReducer

The useReducer hook is similar to useState, but gives us a more structured approach for updating complex values.

We typically use useReducer when our state has multiple sub-values, e.g. an object containing keys that we want to update independently.


API

The useReducer hook requires 2 arguments, and has an optional 3rd argument:

  • reducer – a pure function that takes a state and an action, and returns a new state value based on the action
  • initialState – any initial state value, just like useState
  • initializer (optional) – a function called to lazily instantiate the initialState (this is uncommon)

The useReducer hook returns the current state, and a dispatch function to update the state.


Example

In this example, we store both a first and last name in a single state object with useReducer.

When we type a new first name, dispatch is called with { type: 'first', value: text } as its argument. This argument gets passed to the reducer as action. Then the reducer follows the switch case logic case 'first' and returns the new state: the current last name (from ...state) and the new first name contained in the action as action.value.

import React, { useReducer } from 'react'
import { View, Text, TextInput } from 'react-native'

function reducer(state, action) {
  switch (action.type) {
    case 'first':
      return { ...state, first: action.value }
    case 'last':
      return { ...state, last: action.value }
  }
}

export default function App() {
  const [state, dispatch] = useReducer(reducer, { first: '', last: '' })

  return (
    <View>
      <TextInput
        style={{ fontSize: 32 }}
        placeholder="First"
        value={state.first}
        onChangeText={(text) => {
          dispatch({ type: 'first', value: text })
        }}
      />
      <TextInput
        style={{ fontSize: 32 }}
        placeholder="Last"
        value={state.last}
        onChangeText={(text) => {
          dispatch({ type: 'last', value: text })
        }}
      />
      <Text style={{ fontSize: 32 }}>
        Hello {state.first} {state.last}
      </Text>
    </View>
  )
}

The result of above example is displayed below :


3. useEffect

We use the useEffect hook to call functions with side effects within our components.


API

The useEffect hook takes 2 arguments:

  • callback – a function with side effects
  • dependencies – an optional array containing dependency values

When our component function runs, the callback will be called if any dependencies have changed since the last time the component function ran.


Example

In this example, we’ll log to the console any time the count is a multiple of 3. The callback is called every time the countEvery3 changes, since countEvery3 is listed as a dependency.

import React, { useState, useEffect } from 'react'
import { Button } from 'react-native'

export default function App() {
  const [count, setCount] = useState(0)
  const countEvery3 = Math.floor(count / 3)

  useEffect(() => {
    console.log(countEvery3)
  }, [countEvery3])

  return (
    <Button
      title={`Increment ${count}`}
      onPress={() => {
        setCount(count + 1)
      }}
    />
  )
}

The result of above example is displayed below :


Undefined or empty dependency array

If the dependency array is empty or undefineduseEffect will have a different behavior:

  • [] – the callback is called only once, right after the component renders for the first time.
  • undefined – the callback is called on every component render (every time the component function runs).


undefined dependencies

Here the dependency array is undefined, so our callback will run every time our component function runs, e.g. any time we click the button and useState tells our component to re-run.

import React, { useState, useEffect } from 'react'
import { Button } from 'react-native'

export default function App() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('Incremented!')
  })

  return (
    <Button
      title={`Increment ${count}`}
      onPress={() => {
        setCount(count + 1)
      }}
    />
  )
}

The result of above example is displayed below :


Empty dependencies

Here the dependency array is empty, so our callback will only run once (and therefore only log one time).

import React, { useState, useEffect } from 'react'
import { Button } from 'react-native'

export default function App() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('Only once!')
  }, [])

  return (
    <Button
      title={`Increment ${count}`}
      onPress={() => {
        setCount(count + 1)
      }}
    />
  )
}

The result of above example is displayed below :


4. useRef

With useRef, we can create and update a single mutable value that exists for the lifetime of the component instance.

After assigning the ref to a variable, we use .current to access the mutable value.


Example

In this example, we store the return value of setInterval, which is an interval id, so that we can later call clearInterval.

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

export default function App() {
  const intervalRef = useRef()
  const [count, setCount] = useState(0)

  useEffect(() => {
    intervalRef.current = setInterval(
      () => setCount((count) => count + 1),
      1000
    )

    return () => {
      clearInterval(intervalRef.current)
    }
  }, [])

  return (
    <View>
      <Text style={{ fontSize: 120 }}>{count}</Text>
      <Button
        title="Stop"
        onPress={() => {
          clearInterval(intervalRef.current)
        }}
      />
    </View>
  )
}

The result of above example is displayed below :


5. Custom Hooks

We can compose built-in hooks to create new ones. We should still use the use prefix for our function name.


Example

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

function useInterval(callback, delay) {
  const savedCallback = useRef()

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback
  }, [callback])

  // Set up the interval.
  useEffect(() => {
    if (delay !== null) {
      let id = setInterval(() => {
        savedCallback.current()
      }, delay)
      return () => clearInterval(id)
    }
  }, [delay])
}

export default function App() {
  const [count, setCount] = useState(0)

  useInterval(() => {
    setCount(count + 1)
  }, 1000)

  return <Text style={{ fontSize: 120 }}>{count}</Text>
}

That’s all about in this article.


Conclusion

In this article, We understood about how to use Hooks in React Native. This article demonstrated In-built Hooks APIs Usage with examples in React Native application.

Thanks for reading ! I hope you enjoyed and learned about the Hook 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!!???

ReactJS – How to Effectively Think In React Hooks ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will understand about the rules of React Hooks and how to effectively start using them in our projects. We will discuss the two most important rules of React Hooks and how to effectively think in Hooks.

” React Hooks are a new addition in React 16.8 that let you use state and other React features without writing a class component. In other words, Hooks are functions that let you “hook into” React state and lifecycle features from function components. (They do not work inside class components.)”

A famous quote about learning is :

” The more I live, the more I learn. The more I learn, the more I realize, the less I know. “

So Let’s begin.


What is React Hook?

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. It mainly uses to handle the state and side effects in react functional component. React Hooks are a way to use stateful functions inside a functional component. Hooks don’t work inside classes — they let you use React without classesReact provides a few built-in Hooks like useState and useEffect. The React hooks do :

  • Best practices
  • Easy to under understand
  • Easy to test
  • Increases the performance and so on.


Why React Hook?

There are two reasons to use React hooks :

  • The first main reason is the Introduce state in a functional component. We know that the states cannot be used in functions. But with hooks, we can use states.
  • Another reason is the handle side effect in react component. It means, now we can use newly introduced state such as useEffect.

But do we should know for some scenarios, there are 3 places where react failsWhile Reuse logic between components :

  • Has Huge components
  • Confusing


Rules Of React Hooks

Hooks are JavaScript functions, but we need to follow two rules when using them :

  1. Call Hooks at the top level;
  2. Only call Hooks from React components.

Let’s look at these rules in more detail :


1. Call Hooks At The Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Always use Hooks at the top level of your React function. By following this rule, we ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

Let’s make a Form component which will have two states:

  • accountName
  • accountDetail

These states will have default values, we’ll make use of the useEffect hook to persist the state to either the local storage of our browser or to the title of our document.

Now, this component will be maybe to successfully manage its state if it remains the same between multiple calls of useState and useEffect.

function Form() {
  // 1. Use the accountName state variable
  const [accountName, setAccountName] = useState('Arun');

  // 2. Use an effect for persisting the form
  useEffect(function persistForm() {
    localStorage.setItem('formData', accountName);
  });

  // 3. Use the accountDetail state variable
  const [accountDetail, setAccountDetail] = useState('Active');

  // 4. Use an effect for updating the title
  useEffect(function updateStatus() {
    document.title = accountName + ' ' + accountDetail;
  });

  // ...
}

If the order of our Hooks changes (which can be possible when they are called in loops or conditionals), React will have a hard time figuring out how to preserve the state of our component.

// ------------
useState('Arun')           // 1. Initialize the accountName state variable with 'Arun'
useEffect(persistForm)     // 2. Add an effect for persisting the form
useState('Active')        // 3. Initialize the accountdetail state variable with 'Active'
useEffect(updateStatus)     // 4. Add an effect for updating the status

// -------------
// Second render
// -------------
useState('Arun')           // 1. Read the accountName state variable (argument is ignored)
useEffect(persistForm)     // 2. Replace the effect for persisting the form
useState('Active')        // 3. Read the accountDetail state variable (argument is ignored)
useEffect(updateStatus)     // 4. Replace the effect for updating the status

// ...

That’s the order React follows to call our hooks. Since the order remains the same, it will be able to preserve the state of our component. But what happens if we put a Hook call inside a condition?

// We're breaking the first rule by using a Hook in a condition
  if (accountName !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', accountName);
    });
  }

The accountName !== '' condition is true on the first render, so we run this Hook. However, on the next render the user might clear the form, making the condition false. Now that we skip this Hook during rendering, the order of the Hook calls becomes different:

useState('Arun')           // 1. Read the accountName state variable (argument is ignored)
// useEffect(persistForm)  // This Hook was skipped!
useState('Active')        // 2 (but was 3). Fail to read the accountDetails state variable
useEffect(updateStatus)     // 3 (but was 4). Fail to replace the effect

React wouldn’t know what to return for the second useState Hook call. React expected that the second Hook call in this component corresponds to the persistForm effect, just like during the previous render — but it doesn’t anymore. From that point on, every next Hook call after the one we skipped would also shift by one — leading to bugs.

This is why Hooks must be called on the top level of our components. If we want to run an effect conditionally, we can put that condition inside our Hook.


2. Only Call Hooks From React Components

Don’t call Hooks from regular JavaScript functions. Instead, you can call Hooks from React function components. Let’s take look at the difference between JavaScript function and React component below:

JavaScript Function

import { useState } = "react";

function toCelsius(fahrenheit) {
  const [name, setName] = useState("Arun");
  return (5/9) * (fahrenheit-32);
}
document.getElementById("demo").innerHTML = toCelsius;

Here we import the useState hook from the React package, and then declared our function. But this is invalid as it is not a React component.

React Function


import React, { useState} from "react";
import ReactDOM from "react-dom";

function Account(props) {
  const [name, setName] = useState("Arun");
  return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p>
}
ReactDom.render(
  <Account total={20} amount={5000} />,
  document.getElementById('root')
);

Even though the body of both looks similar, the latter becomes a component when we import React into the file. This is what makes it possible for us to use things like JSX and React hooks inside.

If we happened to import our preferred hook without importing React (which makes it a regular function), we will not be able to make use of the Hook we’ve imported as the Hook is accessible only in React component.


Call Hooks From Custom Hooks

A custom Hook is a JavaScript function whose name starts with use and that may call other Hooks. For example, useUserName is used below a custom Hook that calls the useState and useEffect hooks. It fetches data from an API, loops through the data, and calls setIsPresent() if the specific username it received is present in the API data.

export default function useUserName(userName) {
  const [isPresent, setIsPresent] = useState(false);
  
  useEffect(() => {
    const data = MockedApi.fetchData();
    data.then((res) => {
      res.forEach((e) => {
        if (e.name === userName) {
          setIsPresent(true);
        }
     });
    });
  });
    
  return isPresent;
}

We can then go on to reuse the functionality of this hook in other places where we need such in our application. In such places, except when needed, we don’t have to call useState or useEffect anymore.

By following this rule, we ensure that all stateful logic in a component is clearly visible from its source code.


Function Component Vs Class Component In Hooks

Let’s take a brief look at class components and functional components (with Hooks), before diving into the few Hooks best practices.

The simplest way to define a component in React is to write a JavaScript function that returns a React element:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

The Welcome component accepts props which is an object that contains data and returns a React element. We can then import and render this component in another component.

The class component uses a programming methodology called Encapsulation which basically means that everything relevant to the class component will live within it. Life-cycle methods (constructorscomponentDidMount()render, and so on) give components a predictable structure.

Encapsulation is one of the fundamentals of OOP (Object-Oriented Programming). It refers to the bundling of data within the methods that operate on that data, and is used to hide the values or state of a structured data object inside a class — preventing unauthorized parties’ direct access to them.

With Hooks, the composition of a component changes from being a combination of life-cycle Hooks — to functionalities with some render at the end.


Function Component

The example below shows how custom Hooks can be used in a functional component (without showcasing what the body is). However, what it does or can do is not limited. It could be instantiating state variables, consuming contexts, subscribing the component to various side effects — or all of the above if you’re using a custom hook!

function {
  useHook{...};
  useHook{...};
  useHook{...};
  return (
    ...
  );
}


Class Component

class component requires you to extend from React.Component and create a render function which returns a React element. This requires more code but will also give you some benefits.

class {
  constructor(props) {...}
  componentDidMount() {...}
  componentWillUnmount() {...}
  render() {...}
}

There are some benefits you get by using functional components in React:

  1. It will get easier to separate container and presentational components because you need to think more about your component’s state if you don’t have access to setState() in your component.
  2. Functional components are much easier to read and test because they are plain JavaScript functions without state or lifecycle-hooks.
  3. You end up with less code.
  4. The React team mentioned that there may be a performance boost for functional components in future React versions.

This leads to the first best practice when using React Hooks.


Hooks Best Practices

There are some best practices in writing Hooks the right and effective way as below:

  1. Simplify Your Hooks
  2. Organize And Structure Your Hooks
  3. Use React Hooks Snippets
  4. Put Hooks Rules into Consideration


1. Simplify Your Hooks

Keeping React Hooks simple will give us the power to effectively control and manipulate what goes on in a component throughout its lifetime. Avoid writing custom Hooks as much as possible; we can inline a useState() or useEffect() instead of creating our own hook.

If we find ourself making use of a bunch of custom Hooks that are related in functionality, we can create a custom hook that acts as a wrapper for these. Let’s take a look at two different functional components with hooks below.

Functional Component v1

function {
  useHook(...);
  useHook(...);
  useHook(...);
  return(
    <div>...</div>
  );
}

Functional Component v2

function {
  useCustomHook(...);
    useHook(...);
    useHook(...);
  return(
    <div>...</div>
  );
}

v2 is a better version because it keeps the hook simple and all other useHooks are inline accordingly. This allows us to create functionality that can be reused across different components and also gives us more power to control and manipulate our components effectively. Instead of adopting v1 in which our components are littered with Hooks, we should make use of v2 which will make debugging easy and our code cleaner.


2. Organize And Structure Your Hooks

One of the advantages of React Hooks is the ability to write less code that is easy to read. In some cases, the amount of useEffect() and useState() can still be confusing. When we keep our component organized it will help in readability and keep the flow of our components consistent and predictable. If our custom Hooks are too complicated, we can always break them down to sub-custom Hooks. Extract the logic of our component to custom Hooks to make our code readable.


3. Use React Hooks Snippets

React Hooks Snippets is a Visual Studio Code extension to make React Hooks easier and faster. Currently, five hooks are supported:

  • useState()
  • useEffect()
  • useContext()
  • useCallback()
  • useMemo()

There are two ways (Command and Extension Marketplace) we can add React Hooks snippets to our project:


4. Put Hooks Rules into Consideration

Endeavor to always put the two rules of Hooks we learned earlier into consideration while working with React Hooks.

  • Only call your Hooks at the top level. Don’t call Hooks inside loops, conditions or nested functions.
  • Always call Hooks from React function components or from custom Hooks, don’t call Hooks from regular JavaScript functions.

The ESlint plugin called eslint-plugin-react-hooks enforces these two rules, we can add this plugin to your project if we’d like it as we explain above in rules of hooks section.

Best practices have not been fully resolved because Hooks are still relatively new. So adoption should be taken with precaution one would take in adopting in any early technology. With that in mind, Hooks are the way for the future of React.

That’s all about in this article.


Conclusion

In this article, We understood about the two most important rules of React Hooks and how to effectively think in Hooks. We looked at functional components and some best practices in writing Hooks the right and effective way. As brief as the rules are, it’s important to make them our guiding compass when writing rules. If we are prone to forget it, we can make use of the ESLint plugin to enforce it.

Thanks for reading ! I hope you enjoyed and learned about the Hook Concepts in ReactJS. 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!!???

Exit mobile version