---
# System prepended metadata

title: React Native (2024/05/10)

---

# React Native (2024/05/10)

*By 鄭宇軒、張巧柔*

## Outline
1. React Native 簡介
2. React Native vs React
3. 建立 React Native 專案
4. 檔案結構
5. 基本元件介紹
    A. View
    B. Text
    C. Image
    D. Button
    E. TextInput
6. 元件 Styles 設計
7. 事件處理
8. 變數狀態管理
9. 頁面路由
10. References
11. 本次作業


## 1. React Native 簡介

接下來要先來好好認識React Native～
>React.js 是一個由 Facebook 開發用於構建使用者界面的 JavaScript 程式庫
這邊舉兩個 React 的主要特點和概念
>1. 組件化： React 採用組件化的開發模式，允許開發者將應用程式劃分為多個獨立的、可重用的組件。每個組件都可以擁有自己的狀態（state）和屬性（props）。
>2. JSX 語法： React 使用一種名為 JSX（JavaScript XML）的語法，允許開發者在 JavaScript 程式中嵌入 HTML 標記，使程式碼更具可讀性。

:::success
React Native是一個移動應用程式開發框架，使用React.js構建移動應用程式，可在Android/ios使用
:::

構成概要:
:::info

1. JavaScript
2. 寫法 <..>…</..>，類似於 HTML
3. 排版和樣式風格style={{}}，類似於 CSS
:::

有點像是 `HTML(.html)`+`CSS(.css)`+`JavaScript(.js)`=>`React Native(jsx)`




## 2. React Native vs React

:::info
**TL;DR**
- React Native ≠ React
- React 是網頁函式庫 (Library)
- React Native 是手機應用框架 (Framework)
- 兩者的語法很類似，但核心處理不一樣
:::

大家可能有聽過另一個叫 React（React.js） 的函式庫（不是框架）。雖然兩者均是 Facebook (Meta) 所創立的，但它們的功用並不相同。React 是純網頁架構，專門用於傳統網頁開發，類似 Angular、Vue 等架構；而 React Native 是專門用作開發手機應用的。

縱使兩者的功用不一樣，但在開發上的相似度很高，不論是架構、語法等都有一定程度類似，開發人員要從兩者之間轉換的難度不高。

在渲染 (Rendering) 層面來看，React 利用 HTML、CSS、JS 等語言來處理網頁內容；而 React Native 則是利用手機平台（Android、iOS）內的元件來進行處理。

簡單而言，React Native 容許開發者以類似網頁開發的模式，開發手機應用。在編譯時，它會將開發者定義的元件，轉換成手機平台上所提供的元件，並進行顯示。


## 3. 建立 React Native 專案

事不宜遲，一邊學習也要一邊實作看看！

首先在想要的資料夾中開啟終端機，輸入以下指令建立一個新檔案
```terminal
npx create-expo-app --template
```
選擇TypeScript的空專案並取個名字，接著打開檔案資料夾，把名為 `App.tsx`的檔案點開
```jsx=
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```
接下來在一邊學習的同時，可以在這邊練習學到的語法


## 4. 檔案結構

React Native 的 Component 共有兩種定義方式 —— Functional Component 和 Class Component。兩者最大差異在於語法，但均能達到一樣的設計效果。

Functional Component 是以函數方式定義，其並沒有自己的狀態變數，可以直接與 React Native 的核心 Lifecycle 溝通。這種定義方式比較簡單易讀，適合只需簡單顯示的元件使用。

```jsx=
const PageOne = () => {
    return (
        <h1>Page One</h1>
    );
}
```

Class Component 則是以 Class，即物件導向的方式定義元件。其內包含自己的狀態參數和 React Native Lifecycle 函數（如 `render()`）。這比較類似於 Vue 的寫法。這種定義方式較複雜，但可以提供更細膩的元件控制。
```jsx=
class App extends Component {
    render () {
        return (
            <Text>Hello World!</Text>
        )
    }
}
```

註：NCUAPP 大部分是使用 Functional Components 的定義方式。

React Native 的元件設計與 HTML 語法很類似，均透過標籤（Tags）來定義。每個 Tag 之間可放入子元件或文字內容。這些設計的部分應透過 `return` 或 `render()` 函數 進行匯出。

而在同一個檔案內，我們可加入 JavaScript (或 TypeScript) 邏輯與變數。


## 5. 基本元件介紹

### A. View
這是最原始的元件，幾乎所有元件都從 View 延伸出來。它與 HTML 中的 `div` 類似，僅最為一個空的元件，可以當作元件容器使用。

```jsx=
<View>
    // 這裡面放其他的子元件...
</View>
```



### B. Text
顯示文字內容使用。與標籤之間填入內容即可。

```jsx=
import { Text } from 'react-native';
```
```jsx=
<Text>Hello, React Native!</Text>
```

### C. Image
顯示圖片使用。必須透過 `source`，填入圖片來源。可以是 URL 或 檔案路徑。

```jsx=
import { Image } from 'react-native';
```
```jsx=
<Image 
    source={{ uri: 'https://example.com/image.jpg' }}
/>
```

### D. Button
可以點擊的按鈕。

`title` 是按鈕上顯示的文字。
`onPress` 可以在點擊按鈕後觸發自定義函數。

```jsx=
import { Button } from 'react-native';
```
```jsx=
// handlePress 是自定義的事件處理函數，下面會說明
<Button 
    title="Press Me" 
    onPress={handlePress} 
/>
```

### E. TextInput
輸入框，可以接受用戶輸入。

`placeholder` 是提示文字，在空白的時候會顯示。
`onChangeText` 可以在數值改變是觸發自定義函數。
`value` 是當前實際數值，會保存於自定義變數中。

```jsx
<TextInput 
    placeholder="Type something..."
    onChangeText={handleTextChange}
    value={text}
/>
```



## 6. 元件 Style 設計
元件預設只有簡單的設計。在一般網頁中，如要使元件附有美觀之設計，則需要額外透過 CSS 來定義外觀設計。在 React Native 中也是同等邏輯。

針對元件的設計，一般會延伸 React Native 之 `Stylesheet`，定義一名為 `styles` 之常數。其為 JSON 格式，可定義不同名稱之設計組別（類似 CSS 的 class）。在每個設計組別內，我們可設定各項設計參數。

```js=
import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  mainContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  mainText: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#333',
  },
  mainImage: {
    width: 200,
    height: 200,
    resizeMode: 'cover',
  },
  mainInput: {
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 5,
    padding: 10,
    marginBottom: 10,
    width: '80%',
  },
});
```

上述例子中定義了 `mainContainer`、`mainText`、`mainImage`、`mainInput` 四個設計組別，各自附有不同設計參數。這些參數與 CSS 非常類似。

要注意的是，由於這是 JavaScript 語法，如要定義較複雜的設計數值（如 `80%`、`#333` 等），需要加上引號（以字串形式表達）。

定義好設計後，則可以應用於 Component 中：

```jsx=
const MyApp = () => {
  return (
    <View style={styles.mainContainer}>
      <Text style={styles.mainText}>Hello, React Native!</Text>
      <Image
        style={styles.mainImage}
      />
      <TextInput
        placeholder="Enter your text"
        style={styles.mainInput}
      />
    </View>
  );
};
```


## 7. 事件處理

事件處理是大部分應用中不可或缺的部分，其負責聆聽使用者之操作，並觸發不同的行為。各個元件均附有不同事件，我們可以將這些事件連結至自定義的函數進行處理。做法與一般網頁類似。

假設要處理按鈕的 `press` （點擊）事件，可以在定義元件時設定 `onPress` 屬性，配上一自定義函數：
```jsx=
// 自定義的處理函數
const handleButtonPress = () => {
    console.log('Button pressed!');
};
```

```jsx=
<View>
    <Button
        title="Press Me"
        onPress={handleButtonPress}
    />
</View>
```



## 8. 變數狀態管理

React Native 中共分成 `props` 和 `state`。`props` 是由上層 Component 傳下來的輸入值，而 `state` 則為每個 Component 自身內定義的變數。

要使用 `state`，必須先匯入 `useState` 方法：
```jsx
import { useState } from 'react';
```

接著在 Component function 中，利用 `useState` 定義所需的變數：
```jsx=
const PageOne = () => {
    const [myVariable, setMyVariable] = useState(0);    // 括號內填入初始值，可以為其他種類
    
    const updateMyVariable = () => {
        setMyVariable(myVariable + 1)    // 將 myVariable 增加 1
    }
    
    return {
        <View>
            <Text>{myVariable}</Text>    // 文字上顯示 myVariable 的數字
        </View>
    }
}
```

每個變數均需要以 `[myVariable, setMyVariable]` 的形式定義。`myVariable` 為實際變數名稱，而 `setMyVariable` 則為設定 `myVariable` 數值的方法。

在 `return` 部分中，我們可以直接利用 `myVariable` 作顯示或判斷。

而在其他函數中，如 `updateMyVariable` 中，也可以直接讀取 `myVariable`。亦可以透過 `setMyVariable`，更新 `myVariable` 的數值。

## 9. 頁面路由

頁面路由需要額外套件達成。
```bash
npx expo install @react-navigation/native @react-navigation/native-stack
```

```bash
npx expo install react-native-gesture-handler
```

```bash=
npx expo install @react-navigation/stack
```

接著在 App.jsx 中，需 return `NavigationContainer`:
```jsx=
import * from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';

const Stack = createStackNavigator();
const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;
```

`NavigationContainer` 是最外層的容器
`Stack` 是一個頁面堆疊，即頁面會一個一個往上疊，像壽司盤子一樣

每個頁面則透過 `Stack.Screen` 定義。須填入 `name` 和要顯示的 `Component`。

接著在 Component 中，需接受一 `navigation` 輸入值。如要切換頁面，使用 navigation.navigate 即可。

```jsx=
const HomeScreen = ({navigation}) => {
  return (
    <Button
      title="Show Details"
      onPress={() =>
        navigation.navigate('Details')
      }
    />
  );
};
```

## References
- [React.js vs React Native](https://www.freecodecamp.org/news/react-js-vs-react-native-whats-the-difference/)
- [what is the different between class component and function component - React Native - StackOverflow](https://stackoverflow.com/questions/60487932/what-is-the-different-between-class-component-and-function-component-react-nat)
- [Functional vs Class Components in React Native](https://www.freecodecamp.org/news/functional-vs-class-components-react-native/)
- [Navigation - React Native](https://reactnative.dev/docs/navigation)
- [Stack Navigator](https://reactnavigation.org/docs/stack-navigator/)
- [State - React Native](https://reactnative.dev/docs/state?language=javascript)
- [React Native Hooks & How To Use useState and useEffect](https://webcache.googleusercontent.com/search?q=cache:https://mobile-dev-console.medium.com/react-native-hooks-how-to-use-usestate-and-useeffect-20f60ee93f9c)
- [React Native 從0開始｜環境架設及建立啟動專案，使用 React Native Cli / Expo 兩種方式！](https://molly1024.medium.com/react-native-%E5%BE%9E0%E9%96%8B%E5%A7%8B-%E7%92%B0%E5%A2%83%E6%9E%B6%E8%A8%AD%E5%8F%8A%E5%BB%BA%E7%AB%8B%E5%95%9F%E5%8B%95%E5%B0%88%E6%A1%88-148eb64096b9)
- [React Native是什麼？](https://ithelp.ithome.com.tw/articles/10233278)
- [NCU APP week2 - react & react native](https://hackmd.io/@dabbie-rilakkuma/SJuvFUxgn/https%3A%2F%2Fhackmd.io%2F%40dabbie-rilakkuma%2FryXKodCx3)
- [React Native Introduction](https://reactnative.dev/docs/getting-started)


## 本次作業 (2024/05/10)

:::info
**繳交期限：2024/05/24**
:::

:::success
**Be Creative！ 大家加油！**
:::

**利用 React Native，建立兩個頁面。請使用 Stylesheet，對頁面進行設計。**
> 排版相關的部分可參考 [這裡](https://reactnative.dev/docs/flexbox) (是官網提供的相關文件)

第一個為登入頁面，要求如下：

- 最上方顯示粗體置中「NCU APP」字樣
- 包含電郵地址欄位
- 包含密碼欄位，輸入之內容須被隱藏
- 欄位須包含 placeholder，顯示範例格式
- 包含一「登入」按鈕，按下後須觸發事件處理函數
- 處理函數須進行以下動作：
    - 檢查電郵地址是否符合格式。如否（或為空值），顯示「電郵地址格式不符」錯誤訊息。
    - 檢查密碼長度是否 >= 8。如否（或為空值），顯示「密碼格式不符」錯誤訊息，並將密碼欄清空。
    - 若通過數值驗證，先將兩個輸入欄位清空，然後將用戶帶至應用主頁畫面（即第二個頁面）。

第二個頁面為主頁面（Homepage），要求如下：

- 最上方顯示任意一圖片（內容不拘，但請挑選適當的）。寬度須為全寬。
- 最下方放置一「登出」按鈕。按下後，切換至登入頁面。

**完成後，請截圖（兩個頁面），或錄製操作影片（更好），並上傳至群組中。**