sub-title

Also check Orama's Quora and Orama's GitHub
I shall not claim to know so much, but only that I learn new things everyday

Friday, 8 April 2022

Mobile Application with React Native and REST API

I was once asked by a client to convert an existing data-driven web application to a mobile application. To the client, it sounded as easy as simply clicking a button to do the required conversion. Unknown and unbelievable to the client, I would have to sit down and develop a new system (or two new systems to be able to use both iOS and Android). To sum it up, it is not as easy and cheap as it might appear to develop a mobile app even if there is already a corresponding web app.

The requested mobile app would have to make HTTP requests to perform CRUD operations on the backend. REST API comes to a developer’s mind immediately. The only advantage - perhaps - was that I already have the necessary endpoints in the backend. When I find an opportunity later, I will make a post about offline-first mobile implementation, but for now it is worth knowing that it isn't easy sailing.

But the user also naturally wanted offline capabilities of the mobile application - which was understandable. However, this only makes development more complicated and costly. Offline capabilities wound ensure that the user would continue entering or accessing data even without connectivity; it would also make saving data faster because that would be done locally, right?

The development of mobile apps that is platform-agnostic has not been any easier until the advent of React Native. For instance, prior to React Native, mobile apps would have to be developed separately for Androids (using Java or Kotlin) and iOS (using Objective-C or Swift). With React Native, one can develop an application that would run on both platforms.

React Native is a UI development library that uses Javascript and React functionalities. Both React (ReactJS) and React Native use the concepts of props, state, components and JSX. However, React Native uses native components (<View>, <Text>, <TextInput>, <Image>, etc) while ReactJS would use web components or HTML code (<div>, <p>, <input>, <img>, etc) as corresponding tags for rendering.

For development, we can use Expo Client or Expo Snacks (web) for the development and simulation of iOS and Android mobile app.


1. Using Expo Client (e
xpo-cli) - the command line interface between developer and expo tools

  • node must be installed (to confirm, check for node version: node –v)
  • check react-native version: react-native -v

Install expo-cli (npm install --global expo-cli)

  • Download expo-cli
  • open the command prompt and run it as administrator.
  • recommended  npm uninstall --global expo-cli.
  • run the command  npm cache clean --force.
  • run the command npm cache verify .
  • now run the command npm install --global expo-cli (also used to upgrade to latest version)

Run expo-cli
At the project folder, type: npm start
Server starts and a browser page opens

For iOS and Android, use Expo Go to run apps that are served through Expo Cli

Common issues with expo-cli
If ExpoGo is not starting on phone (just showing icon). Try to resolve using the following in phone: Settings/Apps/ExpoGo/Storage/ClearData

If you get message “something went wrong”: Make sure the computer and phone are connected on same wifi (understand this clearly)


2. Expo Snacks (web version)

https://snack.expo.dev/@rorama


Soft landing

For a soft landing, a simple “Hello World” example mobile application code below might be of help

App.js
import React from 'react';
import { Text, View } from 'react-native';

const HelloWorldApp = () => {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center"
}}>
<Text>Hello, world!</Text>
</View>
)
}
export default HelloWorldApp;


API Call implementation using Fetch

Now that we are done with the basics of React Native environment setup and Hello World code sample, let us go to REST API implementation. In this case, we assume that we have a resource on some other domain that we want to consume. In real life, our mobile app cannot itself contain every resource that it requires. Therefore, from time to time we have to make API calls to retrieve or update resources from elsewhere.

In this post, I will simply show the HTTP request/response cycle in React Native with a REST API implementation. Once again, React Native provides the Fetch API for networking needs i.e. for accessing or making changes to resources.  The Fetch implementation is as simple as the one used in Vanilla Javascript.

A full self-explanatory, multi-component example of a REST API call with React Native is below, but it requires basic understanding of React Native (props, state, components ...). Note that I have shared two versions of the API call for comparison: FetchApi (using procedural method) and FetchApiClass (using OOP method). I hope this helps.


App.js - the main application

import React, { useState } from "react"; //Import React and useState hook
import { StyleSheet, View, Button, FlatList, Image, Alert, TouchableOpacity } from "react-native"; //Import React native components

//Import these components of the project into the app component
import FetchApi from "./components/FetchApi";
import FetchApiClass from "./components/FetchApiClass";

export default function App() {
  //Return the components while passing props to each component
  return (
    <View>
      <Header title="Fetch API Call"></Header>       
      <View style={styles.screen}>
      	<FetchApi/> //using procedural method
      </View>
      <View style={styles.screen}>
      	<FetchApiClass/> //using OOP method
      </View>               
    </View>
  );
}

//Add styling to components using StyleSheet
const styles = StyleSheet.create({
  screen: {
    paddingTop: 70,
    paddingHorizontal: 70
  },
  screenlist: {
    marginLeft: 20,
    marginRight: 20,
    backgroundColor: 'inherit',
    color: "red",
    paddingLeft: 20,
    paddingRight: 20,
  },
});


Header.js- for displaying header title
import React from "react"; //import React
import { StyleSheet, View, Text } from "react-native"; //import React Native components
 
//Return Header text along with style
const Header = props => { 
  return (
	<View style={styles.header}>
	  <Text style={styles.headerTitle}>{props.title}</Text>
	</View>
  );
};
 
//Add style to create the Header using StyleSheet
const styles = StyleSheet.create({
  header: {
	width: "100%",
	height: 50,
	paddingTop: 0,
	backgroundColor: "purple",
	alignItems: "center",
	justifyContent: "center"
  },
  headerTitle: {
	color: "white",
	fontSize: 20
  }
});
 
export default Header; //Export the component


FetchApi.js - fetching data from API using procedural method
import React, { useEffect, useState } from 'react';
import { FlatList, Text, View, Button } from 'react-native';

const FetchApi = props => { //this is a component
  const [isLoading, setLoading] = useState(true); //variable (state) and method for updating state respectively in square brackets
  const [data, setData] = useState([]); //array variable (state) and method for updating states respectively in square brackets
  console.log(data);

  const url1 = 'https://rorama.github.io/data/mydata.json';
  const headers = {}; // {mode: "no-cors"};

  useEffect(() => { //to run immediately upon mounting
    fetch(url1, {'headers': headers})
      .then((response) => response.json())
      .then((json) => {
        setLoading(true); 
        setData(json) //this.setData({ data: json });
        })
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
  }, []);
  
  /**
  componentDidMount() { //same as useEffect - run at start
      this.fetchCats();
  }      
  */  
  
  const ItemSeprator = () => <View style={{ //this is a component
      height: 4,
      width: "100%",
      backgroundColor: "rgba(0,0,0,0.1)",
  }} />

  const handleRefresh = () => { //this is a component
      this.setState({ refreshing: false }, ()=>{this.fetchCats()});
  }  

  return (
    <View style={{ flex: 1, padding: 24 }}>      
      {/* if isLoading, show Loading..., else show List */}
      {isLoading ? <Text>Loading...</Text> :
      ( <View style={{ flex: 1, flexDirection: 'column', justifyContent:  'space-between'}}>
          <Text style={{ fontSize: 14, color: 'green', textAlign: 'center', paddingBottom: 10}}>{data.title} - Procedural</Text>
          <ItemSeprator/>
          <FlatList
            data={data.articles}
            keyExtractor = {({ id }, index) => id}
           
            renderItem = {({ item }) => (
              <>
                <Text>{item.id + '. ' + item.title}</Text>
                <ItemSeprator/>
                <handleRefresh/>   
              </>
            )}
          />
        </View>
      )}
    </View>
  );
};

export default FetchApi; //Export the component


FetchApiClass.js - fetching data from API using OOP method
import React, { useEffect, useState } from 'react';
import { FlatList, Text, View, Button } from 'react-native';

const FetchApiClass = props => { //this is a component
  const [isLoading, setLoading] = useState(true); //variable (state) and method for updating state respectively in square brackets
  const [data, setData] = useState([]); //array variable (state) and method for updating states respectively in square brackets
  console.log(data);

  const url1 = 'https://rorama.github.io/data/mydata.json';
  const headers = {}; // {mode: "no-cors"};

  const callFetch = (url) => {  
    fetch(url, {'headers': headers})
      .then((response) => response.json())
      .then((json) => {
        setLoading(true); 
        setData(json) //this.setData({ data: json });
        })
      .catch((error) => alert(error))
      .finally(() => setLoading(false));
  };
  
  const ItemSeprator = () => <View style={{ //this is a component
      height: 4,
      width: "100%",
      backgroundColor: "rgba(0,0,0,0.1)",
  }} />

  const handleRefresh = () => { //this is a component
      this.setState({ refreshing: false }, ()=>{this.fetchCats()});
  }  

  return (
    <View style={{ flex: 1, padding: 24 }}>
      <Button title="Fetch API Class (OOP method)" onPress={() => callFetch(url1)}></Button> {/* button has no style */}
      {/* if isLoading, show Loading..., else show List */}
      {isLoading ? <Text>Loading...</Text> :
      ( <View style={{ flex: 1, flexDirection: 'column', justifyContent:  'space-between'}}>
          <Text style={{ fontSize: 14, color: 'green', textAlign: 'center', paddingBottom: 10}}>{data.title} - OOP</Text>
          <ItemSeprator/>
          <FlatList
            data={data.articles}
            keyExtractor = {({ id }, index) => id}
           
            renderItem = {({ item }) => (
              <>
                <Text>{item.id + '. ' + item.title}</Text>
                <ItemSeprator/>
                <handleRefresh/>   
              </>
            )}
          />
        </View>
      )}
    </View>
  );
};

export default FetchApiClass; //Export the component



Sample output in simulator


No comments:

Post a Comment