๐Ÿ“ฑ ์•ฑ ๊ฐœ๋ฐœ ๐ŸŒฟ ์ค‘๊ธ‰

React Native ์‹ค์ „

JavaScript๋กœ iOS/Android ์•ฑ ๋™์‹œ ๊ฐœ๋ฐœ

โฑ๏ธ 10์‹œ๊ฐ„ ๐Ÿ‘๏ธ 24 ์กฐํšŒ
๐Ÿ“– ๊ฐ•์ขŒ ๋‚ด์šฉ
# React Native ์‹ค์ „ ๊ฐ€์ด๋“œ

## ํ•™์Šต ๋ชฉํ‘œ
JavaScript๋กœ iOS/Android ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ์„ ๊ฐœ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

## 1. React Native๋ž€?
Facebook์ด ๋งŒ๋“  ํฌ๋กœ์Šคํ”Œ๋žซํผ ๋ชจ๋ฐ”์ผ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.
- JavaScript๋กœ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ ๊ฐœ๋ฐœ
- iOS์™€ Android ๋™์‹œ ๊ฐœ๋ฐœ
- React ๋ฌธ๋ฒ• ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
- ํ•ซ ๋ฆฌ๋กœ๋”ฉ ์ง€์›

## 2. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
npx create-expo-app myapp
cd myapp
npx expo start

# ๋˜๋Š” React Native CLI
npx react-native init MyApp
cd MyApp
npx react-native run-android
npx react-native run-ios

## 3. ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ
import { View, Text, Image, ScrollView, TouchableOpacity } from "react-native";

function App() {
return (
<View style={{flex: 1, padding: 20}}>
<Text style={{fontSize: 24}}>Hello</Text>
<Image source={{uri: "https://..."}} style={{width: 100, height: 100}} />
<TouchableOpacity onPress={() => alert("Clicked")}>
<Text>Press Me</Text>
</TouchableOpacity>
</View>
);
}

## 4. ์Šคํƒ€์ผ๋ง
import { StyleSheet } from "react-native";

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
padding: 20,
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#333",
},
button: {
backgroundColor: "#007AFF",
padding: 15,
borderRadius: 10,
alignItems: "center",
},
});

## 5. ์ƒํƒœ ๊ด€๋ฆฌ
import { useState, useEffect } from "react";

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

return (
<View>
<Text>Count: {count}</Text>
<Button title="Add" onPress={() => setCount(count + 1)} />
</View>
);
}

## 6. ๋„ค๋น„๊ฒŒ์ด์…˜
npm install @react-navigation/native @react-navigation/stack

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

const Stack = createStackNavigator();

function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}

// ์ด๋™
navigation.navigate("Detail", { id: 123 });

## 7. API ํ†ต์‹ 
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
fetch("https://api.example.com/items")
.then(res => res.json())
.then(json => {
setData(json);
setLoading(false);
});
}, []);

## 8. FlatList
import { FlatList } from "react-native";

<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.title}</Text>
</View>
)}
onEndReached={loadMore}
refreshing={refreshing}
onRefresh={handleRefresh}
/>

## 9. ๋กœ์ปฌ ์ €์žฅ
import AsyncStorage from "@react-native-async-storage/async-storage";

// ์ €์žฅ
await AsyncStorage.setItem("token", "abc123");

// ์ฝ๊ธฐ
const token = await AsyncStorage.getItem("token");

// ์‚ญ์ œ
await AsyncStorage.removeItem("token");

## 10. ์นด๋ฉ”๋ผ/์ด๋ฏธ์ง€
import * as ImagePicker from "expo-image-picker";

const pickImage = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
quality: 1,
});

setImage(result.assets[0].uri);
}
};

## 11. ํ‘ธ์‹œ ์•Œ๋ฆผ
import * as Notifications from "expo-notifications";

// ๊ถŒํ•œ ์š”์ฒญ
const { status } = await Notifications.requestPermissionsAsync();

// ํ† ํฐ ๊ฐ€์ ธ์˜ค๊ธฐ
const token = await Notifications.getExpoPushTokenAsync();

// ๋กœ์ปฌ ์•Œ๋ฆผ
await Notifications.scheduleNotificationAsync({
content: { title: "์•Œ๋ฆผ", body: "๋ฉ”์‹œ์ง€" },
trigger: { seconds: 5 },
});

## 12. ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ
# Expo
eas build --platform android
eas build --platform ios
eas submit --platform android
eas submit --platform ios

# React Native CLI
cd android && ./gradlew assembleRelease
xcodebuild -workspace ios/App.xcworkspace -scheme App

## ์ถ”์ฒœ ํ•™์Šต ์ˆœ์„œ
1. React ๊ธฐ์ดˆ ๋ณต์Šต
2. ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ ์ตํžˆ๊ธฐ
3. ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌํ˜„
4. API ์—ฐ๋™
5. ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ