Skip to content

React Native

Posted on:January 31, 2023 at 11:56 AM

Basic Concept of React Native

What is React Native

React Native is like ReactDOM. It is a library that allows you to render React components to native mobile UI elements in iOS or Android device.

What React Native does

👉 Rect Components will be compiled

We will write React components and React Native will compile and bundle them to Real Native App code to respective platform equivalents.

Web BrowserAndroidiOsReact Native JSX
<div>ViewGroupUIView<View>
<input>EditTextUITextField<TextInput>
<p>TextViewUITextView<Text>

👉 Logic will not be compiled

React Native will spin up a JavaScript process as part of the native app and it allows this process to talk to the underlying Android or iOS platform.

Expo CLI & React Native CLI

Expo

REACT NATIVE CLI

Getting Started

👉 Running React Native app on your phone

  1. Install Expo CLI

    npm install -g expo-cli
    expo init my-project
  2. Download Expo Go app on your phone

  3. Run npm start to start the development server

  4. Scan the QR code with Expo Go app

  5. Make changes to the code and save and the app will automatically reload

👉 Running React Native app on your simulator

  1. Download Android Studio for Android or Xcode for iOS

    • Open Android Studio and open Virtual Device Manager, create a new device that is available for Play Store with the latest version of Android. Then, launch the emulator.
    • Open Simulator from Xcode and create a new simulator of latest iPhone
  2. Go to the terminal, Press i for iOS simulator or a for Android simulator

  3. We can run both iOS and Android simulator at the same time

  4. Make changes to the code and save and the app will automatically reload

React Native Basics

Expo will take App.js as the entry point of the app.

Core UI Components

<View> is to hold and layout other components.

<ScrollView> is to scroll the content.

<FlatList> will only render the visible items, and all the items that are outside of the screen will be loaded on demand (or rendered lazily).

<FlatList
  data={courseGoals}
  renderItem={itemData => {
    return (
      <View style={styles.goalItem}>
        <Text style={styles.goalText}>{itemData.item.text}</Text>
      </View>
    );
  }}
  keyExtractor={(item, index) => {
    return item.id;
  }}
/>

<Text> is for displaying text.

The <Text> element is unique relative to layout: everything inside is no longer using the Flexbox layout but using text layout. This means that elements inside of a <Text> are no longer rectangles, but wrap when they see the end of the line.

<Text>
  <Text>First part and </Text>
  <Text>second part</Text>
</Text>
// Text container: the text will be inline if the space allowed it
// |First part and second part|

// otherwise, the text will flow as if it was one
// |First part |
// |and second |
// |part       |

<View>
  <Text>First part and </Text>
  <Text>second part</Text>
</View>
// View container: each text is its own block
// |First part and|
// |second part   |

// otherwise, the text will flow in its own block
// |First part |
// |and        |
// |second part|

<Image>

<Image source={require("../assets/images/goal.png")} />

<LinearGradient>

import { LinearGradient } from "expo-linear-gradient";

<LinearGradient
  colors={["#4c669f", "#3b5998", "#192f6a"]}
  style={styles.button}
>
  <Text>Sign in with Facebook</Text>
</LinearGradient>;

<ImageBackground>

import { ImageBackground } from "react-native";

<ImageBackground
  source={require("../assets/images/background.jpg")}
  resizeMode="cover"
  style={styles.image}
  imageStyle={{ opacity: 0.5 }}
/>;

<SafeAreaView>

import { Text, SafeAreaView } from "react-native";

const App = () => (
  <SafeAreaView style={styles.container}>
    <Text style={styles.text}>Page content</Text>
  </SafeAreaView>
);

Styling & Layout

We can style the components in 2 ways:

We can also pass an array of styles - the last style in the array has precedence, so you can use this to inherit styles. This is useful to create a flexible custom components.

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

export const Card = ({ children, style }) => {
  return <View style={[styles.card, style]}>{children}</View>;
};

const styles = StyleSheet.create({
  card: {
    justifyContent: "center",
    alignItems: "center",
    marginTop: 36,
    marginHorizontal: 24,
  },
});
{
  "expo": {
    // ...
    "backgroundColor": "#1e085a"
  }
}
const styles = StyleSheet.create({
  inputContainer: {
    elevation: 4,
    shadowColor: "black",
    shadowOffset: { width: 0, height: 2 },
    shadowRadius: 6,
    shadowOpacity: 0.25,
  },
});

Interactivity & State

<TextInput> is for user input

<TextInput
  style={styles.textInput}
  placeholder="Your course goal!"
  onChangeText={goalInputHandler}
  value={value}
  maxLength={10}
  keybroadType="numeric"
  autoCapitalize="none"
  autoCorrect={false}
/>

<Button>

<Button title="Add Goal" onPress={addGoalHandler} />

<Pressable> is a Core Component wrapper that can detect various stages of press interactions on any of its defined children.

How to create custom buttons?

There’s a common problem when building a custom button on Android: the ripple effect is outside of the button. -> We should move <Pressable> inside of <View>. Then we’ll have,

const CustomButton = ({ title, children }) => {
  const handleOnPress = () => {};

  return (
    <View style={styles.buttonOuterContainer}>
      <Pressable
        onPress={handleOnPress}
        android_ripple={{ color: "#640233" }}
        style={({ pressed }) => [
          styles.buttonInnerContainer,
          pressed ? styles.pressed : null,
        ]}
      >
        <Text style={styles.buttonText}>{title}</Text>
      </Pressable>
    </View>
  );
};

const styles = StyleSheet.create({
  buttonOuterContainer: {
    borderRadius: 28,
    margin: 4,
    overflow: "hidden",
  },
  buttonInnerContainer: {
    backgroundColor: "#72063c",
    paddingVertical: 8,
    paddingHorizontal: 16,
    elevation: 2,
  },
  buttonText: {
    color: "white",
    textAlign: "center",
  },
  pressed: {
    opacity: 0.75,
  },
});

<Modal>

<StatusBar> is to control the app’s status bar.

import { StatusBar } from "expo-status-bar";

<StatusBar style="light" />;

<Alert> Launches an alert dialog with the specified title and message.

static Alert (
  title: string,
  message?: string,
  buttons?: AlertButton[],
);

type AlertButton = {
  text: string;
  onPress: () => void;
  style?: 'default' | 'cancel' | 'destructive'; // ios
};
import { Alert } from "react-native";

Alert.alert("Invalid number!", "Number has to be a number between 1 and 99.", [
  { text: "Okay", style: "destructive", onPress: resetInputHandler },
]);

Icons & Fonts

@expo/vector-icons is a expo embedded library that allows you to use icons from the popular icon libraries like Material Icons, Ionicons, Font Awesome, and Zocial.

import Ionicons from "@expo/vector-icons/Ionicons";

export default function App() {
  return (
    <View style={styles.container}>
      <Ionicons name="md-checkmark-circle" size={32} color="green" />
    </View>
  );
}

Splash Screen & Loading Fonts

Splash Screen is the very first screen the users see when they open up an app on a mobile device. It’s also been called launch screen. This is useful to do tasks that will happen behind the scenes such as making API calls, pre-loading fonts.

import * as SplashScreen from "expo-splash-screen";
import * as Font from "expo-font";

// Keep the splash screen visible while we fetch resources
SplashScreen.preventAutoHideAsync();

export default function App() {
  const [appIsReady, setAppIsReady] = useState(false);

  useEffect(() => {
    async function prepare() {
      try {
        // Pre-load fonts, make any API calls you need to do here
        await Font.loadAsync(Entypo.font);
      } catch (e) {
        console.warn(e);
      } finally {
        // Tell the application to render
        setAppIsReady(true);
      }
    }

    prepare();
  }, []);

  const onLayoutRootView = useCallback(async () => {
    if (appIsReady) {
      // This tells the splash screen to hide immediately! If we call this after
      // `setAppIsReady`, then we may see a blank screen while the app is
      // loading its initial state and rendering its first pixels. So instead,
      // we hide the splash screen once we know the root view has already
      // performed layout.
      await SplashScreen.hideAsync();
    }
  }, [appIsReady]);

  if (!appIsReady) {
    return null;
  }

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

Building Adaptive & Responsive UIs

Setting Dynamic width

Set width and MaxWidth and the same time, so that it will try to take width until it reaches maxWidth.

const styles = StyleSheet.create({
  container: {
    maxWidth: "80%",
    width: 300,
  },
});

Introduce Dimensions API

We can use Dimensions API to get the device width and height. And we can use it as the breakpoint to adjust the UI.

import { Dimensions } from "react-native";

const deviceWidth = Dimensions.get("window").width;
const styles = StyleSheet.create({
  container: {
    marginTop: deviceWidth > 350 ? 34 : 26,
  },
});

Debugging React Native Errors

Chrome Inspector

we can choose ‘Debug JS Remotely’ from the developer menu(by command + D in iOS).

Then we can open the Chrome browser and go to http://localhost:19000/debugger-ui/ to open the inspector. We can see the console, network tabs.

React Dev Tools

You can use the standalone version of React Developer Tools to debug the React component hierarchy.

# install the react-devtools package globally
npm install -g react-devtools

# launch the standalone DevTools app:
react-devtools

It should connect to your simulator within a few seconds.

Debugging application state

Reactotron allows you to inspect central store like Redux or MobX-State-Tree application state

React Native Debugger

This is a standalone app for debugging React Native apps:

brew install --cask react-native-debugger

To enable network inspect tab, we can config defaultNetworkInspect option to true in the config file(in ~/.rndebuggerrc).