React Native超簡單完整示例-tabs、頁面導航、熱更新、用戶行爲分析

初學React Native,若是沒有人指引,會發現好多東西無從下手,但當有人指引後,會發現其實很簡單。這也是本人寫這篇博客的主要緣由,但願能幫到初學者。html

本文不會介紹如何搭建開發環境,若是你尚未搭建,可參考這裏的官方文檔:https://react-native.org/doc/getting-started.html 。node

本文也不會介紹各類組件,太多了,可參考這裏的官方文檔:https://react-native.org/doc/components-and-apis.html 。react

本文將會從建立項目開始,到基本的常見佈局(tabs)多頁面之間的導航,加入熱更新用戶行爲分析功能。總之,我但願告訴你在實際工做中一個React Native App是如何開發出來的。android

每個知識點不會展開來詳細講解,這篇博客只是起到一個指引的做用,能讓你少走一點彎路,少一些本身摸索的時間。ios

第一步:建立項目

固然,前提是你已經搭建好了開發環境。npm

在命令行中,進入你想要放項目文件的地方,我放在D盤的mydocs文件夾下(D:\mydocs\),執行如下命令:json

react-native init 項目名

個人項目名是「test0」,因此完整的命令應該是這樣的:react-native

react-native init test0

因爲須要到外網下載文件,而我朝對網絡是有管制的,所以這個命令可能須要執行較長時間。只要網絡沒有中斷,沒有報錯,就耐心等待吧。api

待命令執行完畢後,在 D:\mydocs\ 目錄下就多了一個 test0 文件夾。裏面有不少已經默認建立好的文件和文件夾。緩存

先來對默認建立的項目文件作個簡單的認識。

用你喜歡的任意編輯器(我喜歡用VS Code)找開這個文件夾。你將看到一個相似這樣的目錄結構:

React Native目錄結構

其中,

/package.json 是包管理的配置文件,要安裝什麼包,可在這裏配置,項目的基本信息,好比項目名、版本號、項目說明、等等,也可在此配置。但大多數狀況下,能夠不用管它。

/index.js 項目的啓動文件。

/App.js 首頁文件,在/index.js中會加載這個文件。

/node_modules 項目中用到的全部包都存放在這個文件夾中。本身的項目文件不要放在這裏。

/android 這裏放的是與Android原生編譯相關的一些文件,做爲一名React Native開發者,通常狀況下也不用去管它。

/ios 這裏放的是與iOS原生編譯相關的一些文件,做爲一名React Native開發者,通常狀況下也不用去管它。

這裏需說明一下,若是你的項目的開發中,須要大量去動 /android 和 /ios 下的代碼,甚至在裏面加入不少業務邏輯,那就說明你的項目開發是存在問題的,通常狀況下,只有在某些與編譯、配置、發佈相關的纔會動到這裏的代碼。

第二步:建立咱們的第一個頁面-Hello React Native

其實,如今咱們已經能夠運行項目了。 react-native init test0 這個命令已經默認爲咱們建立了一個首頁,但我想替換爲我本身的內容。

修改  /App.js ,有如下的代碼替換掉原來的全部代碼:

 1 import React from 'react';
 2 import { SafeAreaView, View, Text } from 'react-native';
 3 
 4 class App extends React.Component {
 5     render() {
 6         return (
 7             <SafeAreaView>
 8                 <View>
 9                     <Text>Hello React Native</Text>
10                 </View>
11             </SafeAreaView>
12         );
13     }
14 };
15 
16 export default App;

默認生成的代碼是hooks語法,但我不喜歡,我更喜歡用class。我以爲class的結構更清晰一些。

第三步:在模擬器中查看運行效果

咱們的第一個頁面已經建立好了,如今須要查看一下運行效果。可用真機調試,但大多數狀況下,用模擬器會更方便一些。

有各類模擬器可供選擇,我喜歡用Android Studio自帶的模擬器。安裝方法一樣見這個文檔:https://react-native.org/doc/getting-started.html 。

打開Android Studio,點擊 Configure -> AVD Manager

Android Studio啓動界面

 

 

在打開的窗口中,就能看到全部你已經建立過的模擬器了。若是你尚未建立過模擬器,就點擊 Create Virtual Device 建立一個。下面是我已經建立好的模擬器。

Android Studio模擬器管理

 

 

點擊後面的綠色三角形,就能啓動模擬器了,啓動後是這個樣子的:

Android Studio模擬器

 

 

再次回到咱們的項目。在命令行中,進入項目文件夾( D:\mydocs\test0\ ),執行如下命令:

react-native run-android

由於我用的是Windows系統,就不演示ios的運行效果了。ios的運行,需在Mac電腦上執行如下命令:

react-native run-ios

一樣,可能須要等待比較長的時間,由於一樣須要到外網下載編譯工具。之後再執行此命令時就會快不少了。(這就是不少碼農們恨透了GFW的主要緣由之一 ^_^)

如下是目前咱們的代碼所運行的效果:

react native hello world

第四步:多個頁面之間的導航

如今咱們的示例只有一個頁面,若是有多個頁面,又應該怎樣從一個頁面跳轉到另外一個頁面呢?

React Native中,有不少包能夠實現此功能。好比:React NavigationReact Native Navigation、等等。

網上有各類文章比較過各類包之間的好壞,但對於通常的應用,其實差異不大。雖然在項目中我通常都使用React Native Navigation,但相對來講,React Navigation使用起來更加簡單、比較容易上手。所以在這個示例中,我選擇使用React Navigation

先建立第二個頁面。

在項目的根目錄下建立一個文件: /one.js 。並加入如下代碼:

 1 import React from 'react';
 2 import { View, Text } from 'react-native';
 3 
 4 class One extends React.Component {
 5     render() {
 6         return (
 8             <View>
 9                 <Text>另外一個頁面</Text>
10             </View>
12         );
13     }
14 };
15 
16 export default One;

而後在 /App.js 中加個按鈕,但願點擊它後能跳轉到 /one.js 。將 /App.js 的代碼修改成下面這樣子:

 1 import React from 'react';
 2 import { SafeAreaView, View, Text, Button } from 'react-native';
 3 
 4 class App extends React.Component {
 5     onPress() {
 6         // TODO: 跳到另外一個頁面
 7     }
 8 
 9     render() {
10         return (
11             <SafeAreaView>
12                 <View>
13                     <Text>Hello React Native</Text>
14                 </View>
15                 <View>
16                     <Button title="點擊我去另外一個頁面" onPress={this.onPress}></Button>
17                 </View>
18             </SafeAreaView>
19         );
20     }
21 };
22 
23 export default App;

接下來須要在 onPress() 方法中加入跳轉的代碼。在這以前,須要先安裝React Navigation包。

在項目的根目錄下執行如下命令(你可能須要先關閉模擬器中打開的App,或者直接關閉模擬器,並結束項目的運行):

npm install @react-navigation/native
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
npm install @react-navigation/stack

而後將 /App.js 中的代碼修改成下面這樣子:

 1 import React from 'react';
 2 import { View, Text, Button } from 'react-native';
 3 import { NavigationContainer } from '@react-navigation/native';
 4 import { createStackNavigator } from '@react-navigation/stack';
 5 import One from './one';
 6 
 7 const Stack = createStackNavigator();
 8 
 9 class Home extends React.Component {
10     onPress = () => {
11         this.props.navigation.navigate('One');
12     }
13 
14     render() {
15         return (
16             <View>
17                 <View>
18                     <Text>Hello React Native</Text>
19                 </View>
20                 <View>
21                     <Button title="點擊我去另外一個頁面" onPress={this.onPress}></Button>
22                 </View>
23             </View>
24         );
25     }
26 };
27 
28 class App extends React.Component {
29     render() {
30         return (
31             <NavigationContainer>
32                 <Stack.Navigator initialRouteName="Home">
33                     <Stack.Screen name="Home" component={Home} />
34                     <Stack.Screen name="One" component={One} />
35                 </Stack.Navigator>
36             </NavigationContainer>
37         );
38     }
39 }
40 
41 export default App;

此次的改動比較大。新加了一個 class Home ,將以前 class App 中的代碼移到了 class Home 中,如今的 class App 是一個維護導航的容器。

留意 class Home 中 onPress() 內的代碼,在這裏,用 navigation.navigate(name) 跳轉到另外一個頁面。經過 class App 中的處理, class Home 的 props 中有了一個 navigation 對象。

再次執行 react-native run-android 在模擬器中查看效果:

react native 導航

 

 

點擊頁面中的Button,就能跳轉到 /one.js 了。

在 /one.js 中,能夠直接點擊左上角的「返回」圖標回到上一頁。但爲了演示如何使用代碼返回到上一頁,我將 /one.js 的代碼修改成下面這樣子:

 1 import React from 'react';
 2 import { View, Text, Button } from 'react-native';
 3 
 4 class One extends React.Component {
 5     onPress = () => {
 6         this.props.navigation.goBack();
 7     }
 8 
 9     render() {
10         return (
11             <View>
12                 <Text>另外一個頁面</Text>
13                 <View>
14                     <Button title="返回" onPress={this.onPress}></Button>
15                 </View>
16             </View>
17         );
18     }
19 };
20 
21 export default One;

在這裏使用了 navigation.goBack() 返回到上一頁。

如今,點擊 /one.js 中的「返回」Button,就能回到上一頁了。

react native 導航,返回上一頁

 navigation 還有個 push() 方法,也是較經常使用的。你能夠試試效果。具體使用方法參考官方文檔:https://react-native.org/doc/navigation.html 。

 

 

第五步:加入選項卡tabs

在App中,比較常見的一種佈局是在底部有一排選項卡tabs。

其實,tabs是由多個頁面組成的,所以,在tabs之間切換,也是在多個頁面之間導航。所以這裏一樣須要用到React Navigation

在項目的根目錄下執行如下命令(一樣,你可能須要先中止項目的運行):

npm install @react-navigation/bottom-tabs

爲了更好的演示效果,加入第三個頁面 /two.js ,代碼以下:

 1 import React from 'react';
 2 import { View, Text } from 'react-native';
 3 
 4 class Two extends React.Component {
 5     render() {
 6         return (
 7             <View>
 8                 <Text>第三個頁面</Text>
 9             </View>
10         );
11     }
12 };
13 
14 export default Two;

在 /App.js 中引入它:

1 import Two from './two';

將以前的

1 import { createStackNavigator } from '@react-navigation/stack';

替換爲:

1 import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

並將以前的

1 const Stack = createStackNavigator();

替換爲:

1 const Tab = createBottomTabNavigator();

而後將 class App 修改成:

 1 class App extends React.Component {
 2     render() {
 3         return (
 4             <NavigationContainer>
 5                 <Tab.Navigator>
 6                     <Tab.Screen name="Home" component={Home} options={{title: 'Javascript'}} />
 7                     <Tab.Screen name="One" component={One} options={{title: 'Python'}} />
 8                     <Tab.Screen name="Two" component={Two} options={{title: 'PHP'}} />
 9                 </Tab.Navigator>
10             </NavigationContainer>
11         );
12     }
13 }

再次在項目根目錄下執行 react-native run-android 查看運行效果:

react native選項卡tabs

 

 

能夠看到在底部出現了一排選項卡tabs。點擊它就能在不一樣頁面之間切換了。

固然,還能夠給tabs加上Icon圖標。這裏就不演示了,懶得去找圖標了。更多內容可參考官方文檔:https://react-native.org/doc/navigation.html 。

第六步:加入熱更新功能

好吧,假設到這裏咱們App的功能已經開發完了。

但就能夠這樣結束了嗎?

固然不行。

咱們老大說過:用React Native作App,卻不作熱更新,那你用React Native幹嗎?

這固然是句玩笑話,但實際狀況確實如此,只要是用React Native開發App,通常都會加入熱更新功能,這是用React Native開發App的最大優點之一。若是將最大的優點都丟棄了,確實說不過去。

在這裏我使用CodePush中國提供的熱更新服務。使用的方法比較簡單,官方的示例文檔已經寫得很清楚了,我就不加說明了,直接上代碼。

官方示例文檔在這裏:http://code-push.cn/docs/1600.htm 。

按照官方文檔安裝好 cpcn-react-native 後,在 /App.js 文件中引入它:

1 import cpcn from "cpcn-react-native";

爲了偷懶,我將官網示例中的代碼直接複製到 class Home 中:

 1 class Home extends React.Component {
 2     constructor(props) {
 3         super(props);
 4         this.state = {
 5             upgradeState: 0,
 6             upgradeAllBytes: 0,
 7             upgradeReceived: 0
 8         };
 9     }
10 
11     onPress = () => {
12         this.props.navigation.navigate('One');
13     }
14 
15     componentDidMount() {
16         cpcn.check({
17             // 檢查是否有新版本後調用此方法
18             checkCallback: (remotePackage, agreeContinueFun) => {
19                 if(remotePackage){
20                     // 若是 remotePackage 有值,表示有新版本可更新。
21                     // 將 this.state.upgradeState 的值設爲1,以顯示提示消息
22                     this.setState({
23                         upgradeState: 1
24                     });
25                 }
26             },
27             // 下載新版本時調用此方法
28             downloadProgressCallback: (downloadProgress) => {
29                 // 更新顯示的下載進度中的數值
30                 this.setState({
31                     upgradeReceived: downloadProgress.receivedBytes,
32                     upgradeAllBytes: downloadProgress.totalBytes
33                 });
34             },
35             // 安裝新版本後調用此方法
36             installedCallback: (restartFun) => {
37                 // 新版本安裝成功了,將 this.state.upgradeState 的值設爲0,以關閉對話框
38                 this.setState({
39                     upgradeState: 0
40                 }, () => {
41                     // 調用此方法重啓App,重啓後將會使用新版本
42                     restartFun(true);
43                 });
44             }
45         });
46     }
47 
48     upgradeContinue = () => {
49         // 用戶肯定更新後,調用此方法以開始更新
50         cpcn.agreeContinue(true);
51         // 將 this.state.upgradeState 的值設爲2,以顯示下載進度
52         this.setState({
53             upgradeState: 2
54         });
55     }
56 
57     render() {
58         return (
59             <>
60                 <View>
61                     <View>
62                         <Text>Hello React Native</Text>
63                     </View>
64                     <View>
65                         <Button title="點擊我去另外一個頁面" onPress={this.onPress}></Button>
66                     </View>
67                 </View>
68                 <Modal
69                     visible={this.state.upgradeState > 0}
70                     transparent={true}>
71                     <View style={{padding:18, backgroundColor:"rgba(10,10,10,0.6)", height:"100%", display:"flex", flexDirection:"row", alignItems:"center"}}>
72                         <View style={{backgroundColor:"#fff", width:"100%", padding:18}}>
73                             {
74                                 this.state.upgradeState == 1
75                                 &&
76                                 <View>
77                                     <View style={{paddingBottom:20}}>
78                                         <Text>發現新版本</Text>
79                                     </View>
80                                     <View>
81                                         <Button title="立刻更新" onPress={this.upgradeContinue}/>
82                                     </View>
83                                 </View>
84                             }
85                             {
86                                 this.state.upgradeState == 2
87                                 &&
88                                 <View>
89                                     <Text style={{textAlign:"center"}}>{this.state.upgradeReceived} / {this.state.upgradeAllBytes}</Text>
90                                 </View>
91                             }
92                         </View>
93                     </View>
94                 </Modal>
95             </>
96         );
97     }
98 };

這就算搞定了。這個App已經有了熱更新功能。

第七步:加入用戶行爲分析功能

這還不算完。在真實開發工做中,一個App上線以後,還須要作的事情還不少,好比須要將錯誤日誌傳到服務器,以方便監控是否存在Bug。再好比,很重要的一點,須要分析用戶的行爲,以方便對產品進行改進。這是公司在運營App時的很重要的參考數據。

以前咱們都是本身寫用戶行爲分析。可是搞得代碼很亂,每次修改和加新的監控都很麻煩,而且咱們本身的分析功能寫得也不是很好。

前段時間偶然發現,CodePush中已經有了用戶行爲分析的功能,因而便向老大提議用這個,結果還受到了老大的表揚。^_^

官方文檔在這裏:http://code-push.cn/docs/1700.htm 。

接下來我在這個示例項目中加入用戶行爲分析。我須要知道個人用戶對哪些內容感興趣,是Javascript,仍是Python?又或者是PHP?

只需爲每一個頁面作個埋點,看用戶訪問哪一個比較多就知道結果了。

因爲以前在作熱更新時已經引入了 cpcn-react-native ,因此不需重複引入。但須要注意的是, cpcn-react-nataive 必須在引入全部組件以前引入,例如我如今的引入順序是這樣子的:

1 import React from 'react';
2 import cpcn from "cpcn-react-native";
3 import { View, Text, Button, Modal } from 'react-native';
4 import { NavigationContainer } from '@react-navigation/native';
5 import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
6 import One from './one';
7 import Two from './two';

而後在 import 語句以後加入如下代碼:

1 cpcn.useFootprint();

再而後修改 /App.js 中的 class Home ,在它的 constructor 中加入埋點:

1 class Home extends React.Component {
2     constructor(props) {
3         super(props);
4         this.footprint('Javascript');
5         // 其它代碼。。。。
6     }
7     // 其它代碼。。。。
8 }

給 /one.js  /two.js 也加入埋點:

1 class One extends React.Component {
2     constructor(props) {
3         super(props);
4         this.footprint('Python');
5     }
6     // 其它代碼。。。。
7 }
1 class Two extends React.Component {
2     constructor(props) {
3         super(props);
4         this.footprint('PHP');
5     }
6     // 其它代碼。。。。
7 }

在 /one.js 中有個Button,我也但願能監控用戶有沒有點擊它。所以給該Button也加個埋點:

1 <Button footprint="點了返回按鈕" title="返回" onPress={this.onPress}></Button>

而後就能夠去CodePush的控制檯中查看分析報表了。下面是個人測試結果:

第八步:如今總應該結束了吧?

結束了嗎?

不,尚未。^_^

好比在上面已經提到過的,在真實的開發工做中,咱們還須要記錄用戶的崩潰日誌。再好比,咱們須要知道咱們的用戶主要分佈在哪些地方。再好比,咱們須要將某些數據作緩存。再好比,咱們須要在服務器發生錯誤時給用戶一個友好的提示。等等等等。。。。。

總之,在實際的開發工做中,開發一個App,比在培訓班作個項目要作的事情多得多。

第九步:結束了

雖然如上面所說,還須要作的事情還不少,但在這篇博客裏我就不寫了。之後有時間再寫吧。

以前曾對本身說,要多寫點博客,便可記錄一些知識點,也可幫到別人。但卻一直沒有作到。下班以後就真的不想再動了。^_^

這是第一次寫這麼長的博客,但願能幫到看這篇博客的你。

相關文章
相關標籤/搜索