初学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\),执行以下命令:

react-native init 项目名

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

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 ,有以下的代码替换掉原来的所有代码:

 import React from 'react';
import { SafeAreaView, View, Text } from 'react-native'; class App extends React.Component {
render() {
return (
<SafeAreaView>
<View>
<Text>Hello React Native</Text>
</View>
</SafeAreaView>
);
}
}; 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\ ),执行以下命令:

react-native run-android

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

react-native run-ios

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

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

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

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

React Native中,有很多包可以实现此功能。比如:React NavigationReact Native Navigation、等等。

网上有各种文章比较过各种包之间的好坏,但对于一般的应用,其实差别不大。虽然在项目中我一般都使用React Native Navigation,但相对来说,React Navigation使用起来更加简单、比较容易上手。因此在这个示例中,我选择使用React Navigation

先创建第二个页面。

在项目的根目录下创建一个文件: /one.js 。并加入以下代码:

 import React from 'react';
import { View, Text } from 'react-native'; class One extends React.Component {
render() {
return (
<View>
<Text>另一个页面</Text>
</View>
);
}
}; export default One;

然后在 /App.js 中加个按钮,希望点击它后能跳转到 /one.js 。将 /App.js 的代码修改为下面这样子:

 import React from 'react';
import { SafeAreaView, View, Text, Button } from 'react-native'; class App extends React.Component {
onPress() {
// TODO: 跳到另一个页面
} render() {
return (
<SafeAreaView>
<View>
<Text>Hello React Native</Text>
</View>
<View>
<Button title="点击我去另一个页面" onPress={this.onPress}></Button>
</View>
</SafeAreaView>
);
}
}; 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 中的代码修改为下面这样子:

 import React from 'react';
import { View, Text, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import One from './one'; const Stack = createStackNavigator(); class Home extends React.Component {
onPress = () => {
this.props.navigation.navigate('One');
} render() {
return (
<View>
<View>
<Text>Hello React Native</Text>
</View>
<View>
<Button title="点击我去另一个页面" onPress={this.onPress}></Button>
</View>
</View>
);
}
}; class App extends React.Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="One" component={One} />
</Stack.Navigator>
</NavigationContainer>
);
}
} 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 的代码修改为下面这样子:

 import React from 'react';
import { View, Text, Button } from 'react-native'; class One extends React.Component {
onPress = () => {
this.props.navigation.goBack();
} render() {
return (
<View>
<Text>另一个页面</Text>
<View>
<Button title="返回" onPress={this.onPress}></Button>
</View>
</View>
);
}
}; export default One;

在这里使用了 navigation.goBack() 返回到上一页。

现在,点击 /one.js 中的“返回”Button,就能回到上一页了。

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

第五步:加入选项卡tabs

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

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

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

npm install @react-navigation/bottom-tabs

为了更好的演示效果,加入第三个页面 /two.js ,代码如下:

 import React from 'react';
import { View, Text } from 'react-native'; class Two extends React.Component {
render() {
return (
<View>
<Text>第三个页面</Text>
</View>
);
}
}; export default Two;

在 /App.js 中引入它:

 import Two from './two';

将之前的

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

替换为:

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

并将之前的

 const Stack = createStackNavigator();

替换为:

 const Tab = createBottomTabNavigator();

然后将 class App 修改为:

 class App extends React.Component {
render() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={Home} options={{title: 'Javascript'}} />
<Tab.Screen name="One" component={One} options={{title: 'Python'}} />
<Tab.Screen name="Two" component={Two} options={{title: 'PHP'}} />
</Tab.Navigator>
</NavigationContainer>
);
}
}

再次在项目根目录下执行 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 文件中引入它:

 import cpcn from "cpcn-react-native";

为了偷懒,我将官网示例中的代码直接复制到 class Home 中:

 class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
upgradeState: 0,
upgradeAllBytes: 0,
upgradeReceived: 0
};
} onPress = () => {
this.props.navigation.navigate('One');
} componentDidMount() {
cpcn.check({
// 检查是否有新版本后调用此方法
checkCallback: (remotePackage, agreeContinueFun) => {
if(remotePackage){
// 如果 remotePackage 有值,表示有新版本可更新。
// 将 this.state.upgradeState 的值设为1,以显示提示消息
this.setState({
upgradeState: 1
});
}
},
// 下载新版本时调用此方法
downloadProgressCallback: (downloadProgress) => {
// 更新显示的下载进度中的数值
this.setState({
upgradeReceived: downloadProgress.receivedBytes,
upgradeAllBytes: downloadProgress.totalBytes
});
},
// 安装新版本后调用此方法
installedCallback: (restartFun) => {
// 新版本安装成功了,将 this.state.upgradeState 的值设为0,以关闭对话框
this.setState({
upgradeState: 0
}, () => {
// 调用此方法重启App,重启后将会使用新版本
restartFun(true);
});
}
});
} upgradeContinue = () => {
// 用户确定更新后,调用此方法以开始更新
cpcn.agreeContinue(true);
// 将 this.state.upgradeState 的值设为2,以显示下载进度
this.setState({
upgradeState: 2
});
} render() {
return (
<>
<View>
<View>
<Text>Hello React Native</Text>
</View>
<View>
<Button title="点击我去另一个页面" onPress={this.onPress}></Button>
</View>
</View>
<Modal
visible={this.state.upgradeState > 0}
transparent={true}>
<View style={{padding:18, backgroundColor:"rgba(10,10,10,0.6)", height:"100%", display:"flex", flexDirection:"row", alignItems:"center"}}>
<View style={{backgroundColor:"#fff", width:"100%", padding:18}}>
{
this.state.upgradeState == 1
&&
<View>
<View style={{paddingBottom:20}}>
<Text>发现新版本</Text>
</View>
<View>
<Button title="马上更新" onPress={this.upgradeContinue}/>
</View>
</View>
}
{
this.state.upgradeState == 2
&&
<View>
<Text style={{textAlign:"center"}}>{this.state.upgradeReceived} / {this.state.upgradeAllBytes}</Text>
</View>
}
</View>
</View>
</Modal>
</>
);
}
};

这就算搞定了。这个App已经有了热更新功能。

第七步:加入用户行为分析功能

这还不算完。在真实开发工作中,一个App上线之后,还需要做的事情还很多,比如需要将错误日志传到服务器,以方便监控是否存在Bug。再比如,很重要的一点,需要分析用户的行为,以方便对产品进行改进。这是公司在运营App时的很重要的参考数据。

之前我们都是自己写用户行为分析。但是搞得代码很乱,每次修改和加新的监控都很麻烦,并且我们自己的分析功能写得也不是很好。

前段时间偶然发现,CodePush中已经有了用户行为分析的功能,于是便向老大提议用这个,结果还受到了老大的表扬。^_^

官方文档在这里:http://code-push.cn/docs/1700.htm 。

接下来我在这个示例项目中加入用户行为分析。我需要知道我的用户对哪些内容感兴趣,是Javascript,还是Python?又或者是PHP?

只需为每个页面做个埋点,看用户访问哪个比较多就知道结果了。

由于之前在做热更新时已经引入了 cpcn-react-native ,所以不需重复引入。但需要注意的是, cpcn-react-nataive 必须在引入所有组件之前引入,例如我现在的引入顺序是这样子的:

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

然后在 import 语句之后加入以下代码:

 cpcn.useFootprint();

再然后修改 /App.js 中的 class Home ,在它的 constructor 中加入埋点:

 class Home extends React.Component {
constructor(props) {
super(props);
this.footprint('Javascript');
// 其它代码。。。。
}
// 其它代码。。。。
}

给 /one.js  /two.js 也加入埋点:

 class One extends React.Component {
constructor(props) {
super(props);
this.footprint('Python');
}
// 其它代码。。。。
}
 class Two extends React.Component {
constructor(props) {
super(props);
this.footprint('PHP');
}
// 其它代码。。。。
}

在 /one.js 中有个Button,我也希望能监控用户有没有点击它。因此给该Button也加个埋点:

 <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. ArrayBlockingQueue和LinkedBlockingQueue的使用

    ArrayBlockingQueue和LinkedBlockingQueue的使用 博客分类: java.util.concurrent   BlockingQueue接口定义了一种阻塞的FIFO q ...

  2. java web之Filter详解

    java web之Filter详解 2012-10-20 0 个评论 作者:chenshufei2 收藏 我要投稿 .概念: Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,W ...

  3. Web 如何搭建自己的个人网站

    如何搭建自己的个人技术博客网站 学习目标 1.[了解]搭建网站需要的web构件和网站运行原理 2.[掌握]如何搭建个人博客网站 学习前言 大家都是学习开发的,相信都接触过百度,新浪,淘宝,京东...等 ...

  4. AJ学IOS 之微博项目实战(4)微博自定义tabBar中间的添加按钮

    AJ分享,必须精品 一:效果图 自定义tabBar实现最下面中间的添加按钮 二:思路 首先在自己的tabBarController中把系统的tabBar设置成自己的tabBar(NYTabBar),这 ...

  5. python实现服务器监控报警消息用微信发送(附代码)

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:NicePython PS:如有需要Python学习资料的小伙伴可以加 ...

  6. E - Max Sum Plus Plus Plus HDU - 1244 (线性区间DP)

    题目大意:  值得注意的一点是题目要求的是这些子段之间的最大整数和.注意和Max Sum Plus Plus这个题目的区别. 题解: 线性区间DP,对每一段考虑取或者不取.定义状态dp[i][j]指的 ...

  7. 5. history

    https://developer.mozilla.org/zh-CN/docs/Web/API/History_API Browser History APIs

  8. Linux常见提权

    常见的linux提权 内核漏洞提权 查看发行版 cat /etc/issue cat /etc/*-release 查看内核版本 uname -a 查看已经安装的程序 dpkg -l rpm -qa ...

  9. 这份Mybatis总结,我觉得你很需要!

    前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y Mybatis应该是国内用得最多的「数据访问层」 ...

  10. ansible playbook loop 翻译

    ansible源文档地址 有时候你想多次重复一个任务. 在计算机编程中,这叫做循环. 常见的 Ansible 循环包括使用文件模块更改几个文件和 / 或目录的所有权,使用用户模块创建多个用户,并重复一 ...