初学React Native,如果没有人指引,会发现好多东西无从下手,但当有人指引后,会发现其实很简单。这也是本人写这篇博客的主要原因,希望能帮到初学者。

本文不会介绍如何搭建开发环境,如果你还没有搭建,可参考这里的官方文档:https://react-native.org/doc/getting-started.html 。

本文也不会介绍各种组件,太多了,可参考这里的官方文档:https://react-native.org/doc/components-and-apis.html 。

本文将会从创建项目开始,到基本的常见布局(tabs)多页面之间的导航,加入热更新用户行为分析功能。总之,我希望告诉你在实际工作中一个React Native App是如何开发出来的。

每一个知识点不会展开来详细讲解,这篇博客只是起到一个指引的作用,能让你少走一点弯路,少一些自己摸索的时间。

第一步:创建项目

当然,前提是你已经搭建好了开发环境。

在命令行中,进入你想要放项目文件的地方,我放在D盘的mydocs文件夹下(D:\mydocs\),执行以下命令:

  1. react-native init 项目名

我的项目名是“test0”,所以完整的命令应该是这样的:

  1. react-native init test0

由于需要到外网下载文件,而我朝对网络是有管制的,因此这个命令可能需要执行较长时间。只要网络没有中断,没有报错,就耐心等待吧。

待命令执行完毕后,在 D:\mydocs\ 目录下就多了一个 test0 文件夹。里面有很多已经默认创建好的文件和文件夹。

先来对默认创建的项目文件做个简单的认识。

用你喜欢的任意编辑器(我喜欢用VS Code)找开这个文件夹。你将看到一个类似这样的目录结构:

其中,

/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

在打开的窗口中,就能看到所有你已经创建过的模拟器了。如果你还没有创建过模拟器,就点击 Create Virtual Device 创建一个。下面是我已经创建好的模拟器。

点击后面的绿色三角形,就能启动模拟器了,启动后是这个样子的:

再次回到我们的项目。在命令行中,进入项目文件夹( D:\mydocs\test0\ ),执行以下命令:

  1. react-native run-android

因为我用的是Windows系统,就不演示ios的运行效果了。ios的运行,需在Mac电脑上执行以下命令:

  1. react-native run-ios

同样,可能需要等待比较长的时间,因为同样需要到外网下载编译工具。以后再执行此命令时就会快很多了。(这就是很多码农们恨透了GFW的主要原因之一 ^_^)

以下是目前我们的代码所运行的效果:

第四步:多个页面之间的导航

现在我们的示例只有一个页面,如果有多个页面,又应该怎样从一个页面跳转到另一个页面呢?

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 (
  7. <View>
  8. <Text>另一个页面</Text>
  9. </View>
  10. );
  11. }
  12. };
  13.  
  14. 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,或者直接关闭模拟器,并结束项目的运行):

  1. npm install @react-navigation/native
  1. npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
  1. 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 在模拟器中查看效果:

点击页面中的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,就能回到上一页了。

navigation 还有个 push() 方法,也是较常用的。你可以试试效果。具体使用方法参考官方文档:https://react-native.org/doc/navigation.html 。

第五步:加入选项卡tabs

在App中,比较常见的一种布局是在底部有一排选项卡tabs。

其实,tabs是由多个页面组成的,因此,在tabs之间切换,也是在多个页面之间导航。因此这里同样需要用到React Navigation

在项目的根目录下执行以下命令(同样,你可能需要先停止项目的运行):

  1. 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 查看运行效果:

可以看到在底部出现了一排选项卡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,比在培训班做个项目要做的事情多得多。

第九步:结束了

虽然如上面所说,还需要做的事情还很多,但在这篇博客里我就不写了。以后有时间再写吧。

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

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

React Native超简单完整示例-tabs、页面导航、热更新、用户行为分析的更多相关文章

  1. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...

  2. React Native移动开发实战-3-实现页面间的数据传递

    React Native使用props来实现页面间数据传递和通信.在React Native中,有两种方式可以存储和传递数据:props(属性)以及state(状态),其中: props通常是在父组件 ...

  3. React Native之使用导航器跳转页面(react-navigation)

    react-navigation是一个导航库,要使用react-navigation来实现跳转页面,首先得在项目中安装此库,由于Yarn是Facebook提供的替代npm的工具,可以加速node模块的 ...

  4. React Native超棒的LayoutAnimation(布局动画)

          该文翻译自:https://medium.com/@Jpoliachik/react-native-s-layoutanimation-is-awesome-4a4d317afd3e#.6 ...

  5. React Native 断点调试 跨域资源加载出错问题的原因分析

    写在前面 ————如果从头开始看还没解决,试试文章最后的绝招 闲来无事,折腾了一下React Native,相比之前,开发体验好了不少.但在真机断点调试那里遇到了跨域资源加载出错的问题,一番探索总算解 ...

  6. 混合开发的大趋势之一React Native之简单的登录界面

    转载请注明出处:王亟亟的大牛之路 这些天都在学习RN这部分吧,然后写了个简单的登陆业务,从"实战"中讲解吧 还是继续安利:https://github.com/ddwhan0123 ...

  7. react native的Navigator组件示例

    import React, {Component} from 'react';import {ScrollView, StyleSheet, Text, View, PixelRatio} from ...

  8. React Native 教程:001 - 如何运行官方控件示例 App

    原文发表于我的技术博客 本文主要讲解了如何运行 React Native 官方控件示例 App,包含了一些 React Native 的基础知识以及相关环境的配置. 原文发表于我的技术博客 React ...

  9. React Native 简介:用 JavaScript 搭建 iOS 应用 (1)

    [编者按]本篇文章的作者是 Joyce Echessa--渥合数位服务创办人,毕业于台湾大学,近年来专注于协助客户进行 App 软体以及网站开发.本篇文章中,作者介绍通过 React Native 框 ...

随机推荐

  1. mysql 不能对同一个表进行 update(delete) 和 select 联合操作

    eq:     update a set  a.x = 1  where a.y  in (select a.x from  a); 上边语法是错误的,在对aupdate 时不能再条件中对同一个a表进 ...

  2. F - Bone Collector

    Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like ...

  3. Zipper 杭电 1501

    Given three strings, you are to determine whether the third string can be formed by combining the ch ...

  4. PHP函数:memory_get_usage

    memory_get_usage()  -返回分配给 PHP 的内存量 说明: memory_get_usage ([ bool $real_usage = false ] ) : int 参数: r ...

  5. 牛顿迭代法的理解与应用( x 的平方根)

    题目来源与LeetCode算法题中的第69题,具体内容如下(点击查看原题): 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只 ...

  6. Exercise

    """ 问:执行完下面的代码后, l,m的内容分别是什么? """ def func(m): for k,v in m.items(): m ...

  7. 聊聊Spring Boot Actuator

    概述 在本文中,我们将介绍Spring Boot Actuator.我们将首先介绍基础知识,然后详细讨论Spring Boot 1.x和2.x中的可用内容. 我们将在Spring Boot 1.x中学 ...

  8. async,await与task.wait()或task.Result的区别

    你是否曾经与我一样不理解async,await与task.wait()或者task.Result的区别? 接下来,一个Demo让你看出他们之间的区别. static void Main(string[ ...

  9. GitHub 如何忽略文件或者文件夹

    在我们开发项目的时候,往往会产生一些不必要的文件,我们会选择忽略他们,不提交到版本控制中,那我们该如何做呢? 步骤一:在项目根目录下,右键,git bash,在弹出的命令行输入框中输入命令:touch ...

  10. Manjaro Linux 入门使用教程

    Manjaro 初体验 Manjaro 是一款基于 Arch LInux 的自由开源发行版,它吸收了 Arch Linux 优秀丰富的软件管理,同时提供了稳定流畅的操作体验.优雅简单是它的追求,稳定实 ...