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,比在培训班作个项目要作的事情多得多。

第九步:结束了

虽然如上面所说,还须要作的事情还不少,但在这篇博客里我就不写了。之后有时间再写吧。

以前曾对本身说,要多写点博客,便可记录一些知识点,也可帮到别人。但却一直没有作到。下班以后就真的不想再动了。^_^

这是第一次写这么长的博客,但愿能帮到看这篇博客的你。

相关文章
相关标签/搜索