Salin dan Bagikan
Cara Membuat Aplikasi Mobile dengan React Native - Panduan lengkap membuat aplikasi mobile Android dan iOS dengan React Native

Cara Membuat Aplikasi Mobile dengan React Native

React Native memungkinkan membuat aplikasi mobile untuk Android dan iOS dengan JavaScript. Mari pelajari dari dasar.

Setup Environment

Prerequisites

# Install Node.js (18+)
# Download dari nodejs.org

# Verify installation
node --version
npm --version

Install React Native CLI

# Install Expo CLI (recommended untuk pemula)
npm install -g expo-cli

# Atau React Native CLI (untuk native modules)
npm install -g react-native-cli

Android Setup

# Install Android Studio
# Download dari developer.android.com

# Set environment variables (Linux/Mac)
export ANDROID_HOME=$HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-tools

# Verify
adb --version

Create New Project

With Expo

# Create project
npx create-expo-app MyApp
cd MyApp

# Start development
npx expo start

# Run on device
# - Scan QR code dengan Expo Go app
# - Atau tekan 'a' untuk Android emulator
# - Atau tekan 'i' untuk iOS simulator

With React Native CLI

# Create project
npx react-native init MyApp
cd MyApp

# Run on Android
npx react-native run-android

# Run on iOS
npx react-native run-ios

Basic Components

View dan Text

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

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Hello React Native!</Text>
      <Text style={styles.subtitle}>Ini adalah aplikasi pertama saya</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#f5f5f5",
  },
  title: {
    fontSize: 24,
    fontWeight: "bold",
    color: "#333",
  },
  subtitle: {
    fontSize: 16,
    color: "#666",
    marginTop: 10,
  },
});

Button dan TouchableOpacity

import { Button, TouchableOpacity, Alert } from "react-native";

function MyComponent() {
  const handlePress = () => {
    Alert.alert("Halo!", "Button ditekan");
  };

  return (
    <View>
      {/* Basic Button */}
      <Button title="Tekan Saya" onPress={handlePress} color="#007AFF" />

      {/* Custom Button dengan TouchableOpacity */}
      <TouchableOpacity
        style={styles.customButton}
        onPress={handlePress}
        activeOpacity={0.7}
      >
        <Text style={styles.buttonText}>Custom Button</Text>
      </TouchableOpacity>
    </View>
  );
}

Image

import { Image } from "react-native";

function MyComponent() {
  return (
    <View>
      {/* Local image */}
      <Image
        source={require("./assets/logo.png")}
        style={{ width: 100, height: 100 }}
      />

      {/* Remote image */}
      <Image
        source={{ uri: "https://example.com/image.png" }}
        style={{ width: 200, height: 200 }}
        resizeMode="cover"
      />
    </View>
  );
}

Input dan Forms

TextInput

import { TextInput } from "react-native";
import { useState } from "react";

function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  return (
    <View style={styles.form}>
      <TextInput
        style={styles.input}
        placeholder="Email"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
        autoCapitalize="none"
      />

      <TextInput
        style={styles.input}
        placeholder="Password"
        value={password}
        onChangeText={setPassword}
        secureTextEntry={true}
      />

      <Button title="Login" onPress={() => console.log(email, password)} />
    </View>
  );
}

const styles = StyleSheet.create({
  form: {
    padding: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: "#ddd",
    padding: 15,
    marginBottom: 15,
    borderRadius: 8,
    fontSize: 16,
  },
});

Lists

FlatList

import { FlatList } from "react-native";

function TodoList() {
  const todos = [
    { id: "1", title: "Belajar React Native" },
    { id: "2", title: "Buat aplikasi pertama" },
    { id: "3", title: "Deploy ke Play Store" },
  ];

  const renderItem = ({ item }) => (
    <View style={styles.todoItem}>
      <Text>{item.title}</Text>
    </View>
  );

  return (
    <FlatList
      data={todos}
      renderItem={renderItem}
      keyExtractor={(item) => item.id}
      ItemSeparatorComponent={() => <View style={styles.separator} />}
    />
  );
}

ScrollView

import { ScrollView } from "react-native";

function LongContent() {
  return (
    <ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
      <Text style={styles.paragraph}>Paragraf 1...</Text>
      <Text style={styles.paragraph}>Paragraf 2...</Text>
      <Text style={styles.paragraph}>Paragraf 3...</Text>
      {/* More content */}
    </ScrollView>
  );
}

Install React Navigation

# Install core
npm install @react-navigation/native

# Install dependencies
npx expo install react-native-screens react-native-safe-area-context

# Install stack navigator
npm install @react-navigation/native-stack

Stack Navigation

import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

const Stack = createNativeStackNavigator();

function HomeScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate("Details", { itemId: 123 })}
      />
    </View>
  );
}

function DetailsScreen({ route, navigation }) {
  const { itemId } = route.params;

  return (
    <View style={styles.container}>
      <Text>Details Screen</Text>
      <Text>Item ID: {itemId}</Text>
      <Button title="Go Back" onPress={() => navigation.goBack()} />
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Tab Navigation

import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Ionicons } from "@expo/vector-icons";

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;
            if (route.name === "Home") {
              iconName = focused ? "home" : "home-outline";
            } else if (route.name === "Profile") {
              iconName = focused ? "person" : "person-outline";
            }
            return <Ionicons name={iconName} size={size} color={color} />;
          },
        })}
      >
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Profile" component={ProfileScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

State Management

useState

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <Text style={styles.count}>{count}</Text>
      <View style={styles.buttons}>
        <Button title="-" onPress={() => setCount(count - 1)} />
        <Button title="+" onPress={() => setCount(count + 1)} />
      </View>
    </View>
  );
}

useEffect

import { useState, useEffect } from "react";

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch("https://api.example.com/data")
      .then((response) => response.json())
      .then((json) => {
        setData(json);
        setLoading(false);
      })
      .catch((error) => {
        console.error(error);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <ActivityIndicator size="large" />;
  }

  return (
    <View>
      <Text>{JSON.stringify(data)}</Text>
    </View>
  );
}

Styling

Flexbox Layout

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: "row", // 'column' default
    justifyContent: "space-between",
    alignItems: "center",
    padding: 20,
  },
  box: {
    width: 100,
    height: 100,
    backgroundColor: "#007AFF",
  },
});

Responsive Design

import { Dimensions, useWindowDimensions } from "react-native";

function ResponsiveComponent() {
  const { width, height } = useWindowDimensions();
  const isLandscape = width > height;

  return (
    <View
      style={[
        styles.container,
        { flexDirection: isLandscape ? "row" : "column" },
      ]}
    >
      <Text>Width: {width}</Text>
      <Text>Height: {height}</Text>
    </View>
  );
}

API Integration

Fetch Data

const fetchUsers = async () => {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("Error fetching users:", error);
    throw error;
  }
};

// POST request
const createUser = async (userData) => {
  try {
    const response = await fetch("https://api.example.com/users", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(userData),
    });
    return await response.json();
  } catch (error) {
    console.error("Error creating user:", error);
    throw error;
  }
};

Build dan Deploy

Build APK (Android)

# Expo
npx expo build:android

# EAS Build (recommended)
npm install -g eas-cli
eas build -p android

# React Native CLI
cd android
./gradlew assembleRelease

Build iOS

# Expo
npx expo build:ios

# EAS Build
eas build -p ios

# Note: iOS requires Apple Developer account ($99/year)

Kesimpulan

React Native adalah cara efisien untuk membuat aplikasi mobile cross-platform. Mulai dengan Expo untuk development lebih mudah, lalu migrate ke bare workflow jika butuh native modules.

Artikel Terkait

Link Postingan : https://www.tirinfo.com/cara-membuat-aplikasi-react-native/

Hendra WIjaya
Tirinfo
5 minutes.
7 January 2026