Front/React

React Native ์‹œ์ž‘ํ•˜๊ธฐ

oodada 2024. 11. 2. 22:49

React Native ์‹œ์ž‘ํ•˜๊ธฐ ๐Ÿ“ฑ

๋ชฉ์ฐจ

  1. React Native ์†Œ๊ฐœ
  2. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •
  3. ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ
  4. ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  5. ์‹ค์Šต ์˜ˆ์ œ
  6. ๋‹ค์Œ ํ•™์Šต ์ฃผ์ œ

ํ•™์Šต ํŒ ๐Ÿ’ก

  • ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ž์ฃผ ์ฐธ๊ณ ํ•˜์„ธ์š”
  • Expo Snack์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ—˜ํ•ด๋ณด์„ธ์š”
  • ์ž‘์€ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”
  • ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜์„ธ์š”
  • ์Šคํƒ€์ผ๋ง์— ์‹œ๊ฐ„์„ ํˆฌ์žํ•˜์„ธ์š”

1. React Native๋ž€?

https://reactnative.dev/
https://expo.dev/

React Native๋Š” ํŽ˜์ด์Šค๋ถ์ด ๊ฐœ๋ฐœํ•œ ๋ชจ๋ฐ”์ผ ์•ฑ ๊ฐœ๋ฐœ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. React์˜ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ iOS์™€ Android ์•ฑ์„ ๋™์‹œ์— ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์žฅ์ 

  • ํ•˜๋‚˜์˜ ์ฝ”๋“œ๋กœ iOS/Android ๊ฐœ๋ฐœ ๊ฐ€๋Šฅ
  • JavaScript/React ์ง€์‹ ํ™œ์šฉ ๊ฐ€๋Šฅ
  • ๋น ๋ฅธ ๊ฐœ๋ฐœ ์†๋„์™€ ์‹ค์‹œ๊ฐ„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ (Hot Reload)
  • ๋„ค์ดํ‹ฐ๋ธŒ ์„ฑ๋Šฅ ์ œ๊ณต

React vs React Native

// React (์›น)
<div>
  <h1>์•ˆ๋…•ํ•˜์„ธ์š”</h1>
  <p>ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค</p>
</div>

// React Native (๋ชจ๋ฐ”์ผ)
<View>
  <Text>์•ˆ๋…•ํ•˜์„ธ์š”</Text>
  <Text>ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค</Text>
</View>

2. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •

ํ•„์ˆ˜ ์„ค์น˜ ํ•ญ๋ชฉ

https://docs.expo.dev/get-started/create-a-project/

  1. Node.js
  2. npm ๋˜๋Š” yarn
  3. Expo CLI ๋˜๋Š” React Native CLI
  4. Android Studio (์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์‹œ)
  5. Xcode (iOS ๊ฐœ๋ฐœ์‹œ, Mac ํ•„์ˆ˜)

Expo CLI๋กœ ์‹œ์ž‘ํ•˜๊ธฐ

# Expo CLI ์„ค์น˜
npm install -g expo-cli

# ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
expo init MyFirstApp

# ํ”„๋กœ์ ํŠธ ์‹คํ–‰
cd MyFirstApp
npm start

3. ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ

์ฃผ์š” ์ปดํฌ๋„ŒํŠธ

https://reactnative.dev/docs/components-and-apis

  • View: ๋ ˆ์ด์•„์›ƒ์„ ๊ตฌ์„ฑํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ
  • Text: ํ…์ŠคํŠธ ํ‘œ์‹œ
  • Image: ์ด๋ฏธ์ง€ ํ‘œ์‹œ
  • ScrollView: ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•œ ์˜์—ญ
  • TextInput: ์ž…๋ ฅ ํ•„๋“œ
import { View, Text, Image, ScrollView, TextInput } from 'react-native';

function App() {
  return (
    <View style={{ flex: 1, padding: 20 }}>
      {/* ํ…์ŠคํŠธ ํ‘œ์‹œ */}
      <Text>์•ˆ๋…•ํ•˜์„ธ์š”!</Text>

      {/* ์ด๋ฏธ์ง€ ํ‘œ์‹œ */}
      <Image
        source={require('./assets/icon.png')}
        style={{ width: 100, height: 100 }}
      />

      {/* ์ž…๋ ฅ ํ•„๋“œ */}
      <TextInput
        style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
        placeholder="์—ฌ๊ธฐ์— ์ž…๋ ฅํ•˜์„ธ์š”"
      />

      {/* ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•œ ์˜์—ญ */}
      <ScrollView>
        <Text>์Šคํฌ๋กค ๋‚ด์šฉ...</Text>
      </ScrollView>
    </View>
  );
}

๊ธฐ๋ณธ ์Šคํƒ€์ผ๋ง

https://reactnative.dev/docs/style

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 20,
    color: 'blue',
    marginBottom: 10,
  },
});

function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>์Šคํƒ€์ผ ์˜ˆ์‹œ</Text>
    </View>
  );
}

4. ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ๊ตฌํ˜„

์ปดํฌ๋„ŒํŠธ : https://reactnative.dev/docs/components-and-apis

๋ฒ„ํŠผ๊ณผ ํ„ฐ์น˜ ์ด๋ฒคํŠธ

https://reactnative.dev/docs/button

import { TouchableOpacity, Alert } from 'react-native';

function MyButton() {
  return (
    <TouchableOpacity
      style={{ padding: 10, backgroundColor: 'blue' }}
      onPress={() => Alert.alert('๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์Šต๋‹ˆ๋‹ค!')}
    >
      <Text style={{ color: 'white' }}>๋ˆŒ๋Ÿฌ๋ณด์„ธ์š”</Text>
    </TouchableOpacity>
  );
}

์ƒํƒœ ๊ด€๋ฆฌ

https://reactnative.dev/docs/intro-react#state

import { useState } from 'react';

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

  return (
    <View>
      <Text>์นด์šดํŠธ: {count}</Text>
      <TouchableOpacity onPress={() => setCount(count + 1)}>
        <Text>์ฆ๊ฐ€</Text>
      </TouchableOpacity>
    </View>
  );
}

5. ์‹ค์Šต ์˜ˆ์ œ: ๊ฐ„๋‹จํ•œ ํ• ์ผ ๋ชฉ๋ก ์•ฑ

import React, { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet } from 'react-native';

export default function TodoApp() {
  const [task, setTask] = useState('');
  const [tasks, setTasks] = useState([]);

  const addTask = () => {
    if (task.trim().length > 0) {
      setTasks([...tasks, { id: Math.random().toString(), text: task }]);
      setTask('');
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>ํ• ์ผ ๋ชฉ๋ก</Text>

      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          value={task}
          onChangeText={setTask}
          placeholder="ํ• ์ผ์„ ์ž…๋ ฅํ•˜์„ธ์š”"
        />
        <TouchableOpacity
          style={styles.addButton}
          onPress={addTask}
        >
          <Text style={styles.buttonText}>์ถ”๊ฐ€</Text>
        </TouchableOpacity>
      </View>

      <FlatList
        data={tasks}
        keyExtractor={item => item.id}
        renderItem={({ item }) => (
          <View style={styles.task}>
            <Text>{item.text}</Text>
          </View>
        )}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#fff',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  inputContainer: {
    flexDirection: 'row',
    marginBottom: 20,
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    marginRight: 10,
    borderRadius: 5,
  },
  addButton: {
    backgroundColor: 'blue',
    padding: 10,
    borderRadius: 5,
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
  },
  task: {
    padding: 15,
    borderBottomWidth: 1,
    borderColor: '#ddd',
  },
});
ํ‹ฐ์Šคํ† ๋ฆฌ ์นœ๊ตฌํ•˜๊ธฐ