React Native
React Native basics
2018/5/30
2019/05/05 (重新整理)
利用expo.io
https://snack.expo.io/ 是個不錯的起點,先下載expo到你的手機上,接下來在https://snack.expo.io/寫的程式碼,就可以直接在你的手機上看成果了 (詳參: Snack — A Playground for React Native)。
打開https://snack.expo.io/就會有一個範例程式檔 App.js:
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Constants } from 'expo';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-elements'; // Version can be specified in package.json
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone!
Save to get a shareable url.
</Text>
<Card title="Local Modules">
<AssetExample />
</Card>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
color: '#34495e',
},
});
在https://snack.expo.io/中,並不需要
AppRegistry.registerComponent('testapp', () => ShowView);
利用VS Code
首先,先安裝react native tools
要安裝node.js,安裝後,根據React Native Getting Started,如果已經安裝了Android Studio或XCode,可以利用React Native CLI:
npm install -g react-native-cli
但是,如果是還沒有安裝Android Studio或XCode:
npm install -g expo-cli
以下範例是以expo為例。
就像使用create-react-app或create-react-native-app一樣,也可以利用expo init產生一個空白的專案:
expo init test-rn
expo init會產生一些設定檔,以及一個App.js,
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
要執行這個專案的話
cd test-rn
npm start
就可以啟動expo的DevTools,DevTools會啟動瀏覽器http://localhost:19002/,讓我們可以利用安裝好的模擬器或利用expo提供的app測試我們寫好的app。
簡單的範例程式 Hello World
我們先參考 ReactNative開發入門教學(1)-HelloWorld 來做一些改變:
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Hello World!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
就會在手機上看到Hello World。
比起寫一個Android App或iOS App來說,這樣的程式其實是相當簡潔。
React native基本介面
加個按鈕
參考 ReactNative開發入門教學(2)-觸發事件 再來做一些改變,首先,將App.js改為:
import React, { Component } from 'react';
import App from './src/app';
export default class Main extends Component {
render() {
return (
<App />
);
}
}
因為在snack.expo.io中,不使用AppRegistry,而是直接使用App.js。
接下來產生一個src目錄,並且新增一個app.js,就如同範例的內容一樣。(src/app.js)
import React, { Component } from 'react';
import {
Text,
View,
TouchableHighlight,
Button
} from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {};
}
_click() {
alert('Clicked!');
}
render() {
return(
<View>
<Button title="Try it!" onPress={this._click.bind(this)}/>
<TouchableHighlight onPress={this._click.bind(this)}>
<Text>HelloWorld!</Text>
</TouchableHighlight>
</View>
);
}
}
export default App;
把前一個範例中的StyleSheet加進來,會看起來好看一點:
import React, { Component } from 'react';
import {
Text,
View,
TouchableHighlight,
Button,
StyleSheet
} from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {};
}
_click() {
alert('Clicked!');
}
render() {
return(
<View style={styles.container}>
<Button title="Try it!" onPress={this._click.bind(this)}/>
<TouchableHighlight onPress={this._click.bind(this)}>
<Text>HelloWorld!</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
export default App;
程式改完之後,會自動reload。
這個範例用到兩個元件:
分頁
- 簡單的分頁範例,使用react navigation提供的TabNavigator (詳參: Tab navigation)
- Navigating Between Screens
- Navigation views
- ReactNative開發入門教學(5)-Navigation實現多頁,畫面跳轉,翻頁 (內容較舊,不適用react navigation 3.x)
最好要把程式碼做一些基本的切割,例如,將HomeScreen 及 DetailsScreen切成兩個檔案放在src路徑下,App.js會改成:
// 2019/05/04 revised for react navigation 3.x
// https://reactnavigation.org/docs/en/tab-based-navigation.html
import React from 'react';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import HomeScreen from './src/home';
import DetailsScreen from './src/details';
const TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
export default createAppContainer(TabNavigator);
src/home.js
import React from 'react';
import { View, Text, Button } from 'react-native';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
export default HomeScreen;
src/details.js
import React from 'react';
import { View, Text, Button } from 'react-native';
class DetailsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
export default DetailsScreen;
**注意** 在exop.io會自動去下載用到的package,如果是使用vs code,就要手動安裝,先利用ctrl-C把npm停下來,執行
npm install react-navigation
npm start
使用ScrollView
使用List
- Using List Views (FlatList 或 SectionList)
- How to use the FlatList Component — React Native Basics
- ListItem的用法是舊版的
- How to highlight and multi-select items in a FlatList component- React Native
import React from 'react';
import { StyleSheet, View, Text, FlatList } from 'react-native';
export default class FlatListScreen extends React.Component {
render() {
return ( <View style={styles.container}>
<FlatList
data={[
{key: 'Devin'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'},
]}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</View>);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22
},
item: {
padding: 10,
fontSize: 18,
height: 44,
},
})
App.js加入FlatListScreen:
// revised for react navigation 3.x
// https://reactnavigation.org/docs/en/tab-based-navigation.html
import React from 'react';
//import { TabNavigator } from 'react-navigation';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import HomeScreen from './src/home';
import DetailsScreen from './src/details';
import FlatListScreen from "./src/FlatListScreen";
const TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Details: DetailsScreen,
"Flat List": FlatListScreen
});
export default createAppContainer(TabNavigator);
react native elements提供的ListItem比FlatList、SectionList還好用,提供了不少的功能,如:avatar、icon、onPress,也可以跟FlatList合併使用。
src/listitemdemo.js
import React from 'react';
import { View, Alert } from 'react-native';
import { ListItem } from 'react-native-elements';
//https://github.com/react-native-training/react-native-elements/issues/349
const list = [
{
title: 'Appointments',
info: 'more info about Appointments',
icon: 'av-timer',
},
{
title: 'Trips',
info: 'more info about Trips',
icon: 'flight-takeoff',
},
];
export default class ListItemDemo extends React.Component {
_onPressButton(item) {
Alert.alert(item.info);
}
render() {
return (
<View>
{list.map((item, i) => (
<ListItem
key={i}
title={item.title}
leftIcon={{ name: item.icon }}
onPress={() => this._onPressButton(item)}
/>
))}
</View>
);
}
}
src/listitemdemo2.js
import React from 'react';
import { View} from 'react-native';
import { ListItem } from 'react-native-elements';
//https://react-native-training.github.io/react-native-elements/docs/listitem.html
const list = [
{
name: 'Amy Farha',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg',
subtitle: 'Vice President',
},
{
name: 'Chris Jackson',
avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg',
subtitle: 'Vice Chairman',
},
];
export default class ListItemDemo2 extends React.Component {
render() {
return (
<View>
{list.map((l, i) => (
<ListItem
key={i}
roundAvatar
//this is the correct way:
leftAvatar={{ source: { uri: l.avatar_url } }}
//avatar={{ uri: l.avatar_url }}
title={l.name}
subtitle={l.subtitle}
/>
))}
</View>
);
}
}
app.js
// revised for react navigation 3.x
// https://reactnavigation.org/docs/en/tab-based-navigation.html
import React from 'react';
//import { TabNavigator } from 'react-navigation';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import HomeScreen from './src/home';
import DetailsScreen from './src/details';
import FlatListScreen from "./src/FlatListScreen";
import ListItemDemo from "./src/listitemdemo";
import ListItemDemo2 from "./src/listitemdemo2";
const TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Details: DetailsScreen,
"Flat List": FlatListScreen,
"ListItem Demo": ListItemDemo,
"ListItem Demo 2": ListItemDemo2
});
export default createAppContainer(TabNavigator);
Form
- How to Validate Forms in React Native — a Personal Approach
- with react-native-form-validation
- Validating Forms in React Native
- with validate.js
資料連接
JSON
- Networking (存取JSON資料) (更多資料: Using Fetch API)
- ReactNative開發入門教學(3)-與伺服器溝通(Fetch)
import React from 'react';
import { FlatList, ActivityIndicator, Text, View } from 'react-native';
export default class MovieScreen extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render(){
//如果還沒完成,出現轉圈圈的AcitivityIndicator
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
<View style={{flex: 1, paddingTop:20}}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={({id}, index) => id}
/>
</View>
);
}
}
跟前面的範例整合起來:
// revised for react navigation 3.x
// https://reactnavigation.org/docs/en/tab-based-navigation.html
import React from 'react';
//import { TabNavigator } from 'react-navigation';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
//import HomeScreen from './src/home';
//import DetailsScreen from './src/details';
import FlatListScreen from "./src/FlatListScreen";
import ListItemDemo from "./src/listitemdemo";
import ListItemDemo2 from "./src/listitemdemo2";
import MovieScreen from "./src/movie";
const TabNavigator = createBottomTabNavigator({
"Flat List": FlatListScreen,
"ListItem Demo": ListItemDemo,
"ListItem Demo 2": ListItemDemo2,
Movie:MovieScreen
});
export default createAppContainer(TabNavigator);
參考資料
- React Native Tutorial
- 內容有點舊....
- React Native Tutorial: Building Android Apps with JavaScript
- React Native IDE 使用VS Code
- 採用react native tool & react-native-cli
- React Native Environment Setup
- 採用react native tool & react-native-cli (on Mac)
- Setting up React Native with Expo, TypeScript, Jest and Visual Studio Code (2017) (on Mac)
- 採用create-react-native-app & expo
- Learning React Native: where to start (2017)
- STEP 1: Get the right equipment
- 建議採用 VS Code
- STEP 2: Read React Native Express
- STEP 3: Learn Navigation
- STEP 4: Dive into the framework
- STEP 1: Get the right equipment
- VSCode for React Native (2017)
- Learn Once, Write Anywhere – 在 Visual Studio Code 開發 ReactNative 應用程式 (2016)
- React Native Debug with VSCode in Simple Steps.