此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源。
最后的章节给大家介绍 React Native 源码的查阅方法,以便你进行更加高阶的开发与研究时参阅,并分享了开发过程中可能遇到的众多问题的解决方案,以及与 React Native 开发相关、本书相关的一些线上资源。
15.6 React Native 源码剖析
我们在学习了 React Native 开发的方方面面之后,我们再次回到 React Native 的本质,给大家简要介绍 React Native 源码的学习方法,对 React Native 源码的整体框架做一个简单介绍,后续如果大家想深入阅读 React Native 框架的源码,希望这部分对你有所帮助,并且能从源码中学习到复杂框架的设计思想,希望大家也能“造出复杂的*”。
React Native 项目的 GitHub 地址为:https://github.com/facebook/react-native,源码的基本结构如图 A-1 所示。
图 A-1 React Native 源码结构
- 根目录中主要包含了项目的一些配置文件和一些描述性文档;
- 初始化项目的 React Native CLI 定义在 react-native-cli 文件夹下;
- RNTester 文件夹包含了 React Native 项目的单元测试用例以及组件、API 的使用示例代码,是一个学习 React Native 组件与 API 使用方法的宝库,这个在之前的章节有过介绍;
- React 文件夹是 iOS 原生平台的项目文件夹,用于与 React Native 的 JavaScript 代码通信;
- ReactAndroid 文件夹是 Android 原生平台的项目文件夹,用于与 React Native 的 JavaScript 代码通信;
- babel-preset 文件夹是 React Native 项目的 Babel 预配置;
- Libraries 文件夹是 React Native 源码的核心,所有的 React Native 组件与 API 的实现都在此文件夹中。
接下来我们就随便找一个组件来看看 React Native 是如何进行实现的,假设我们就来看看 Alert 组件的实现,其实通过我们在 React Native 与原生平台混合开发章节的学习,我们已经大概知道了 React Native 是如何来实现的。
我们先来看 Alert 组件 JavaScript 端的实现,Alert 组件包含的文件如图 A-2 所示。
图 A-2 Alert 组件源码结构
源码在 https://github.com/facebook/react-native/blob/master/Libraries/Alert/Alert.js。
1. ......
2. class Alert {
3.
4. /**
5. * Launches an alert dialog with the specified title and message.
6. *
7. * See http://facebook.github.io/react-native/docs/alert.html#alert
8. */
9. static alert(
10. title: ?string,
11. message?: ?string,
12. buttons?: Buttons,
13. options?: Options,
14. type?: AlertType,
15. ): void {
16. if (Platform.OS === 'ios') {
17. if (typeof type !== 'undefined') {
18. console.warn('Alert.alert() with a 5th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.');
19. AlertIOS.alert(title, message, buttons, type);
20. return;
21. }
22. AlertIOS.alert(title, message, buttons);
23. } else if (Platform.OS === 'android') {
24. AlertAndroid.alert(title, message, buttons, options);
25. }
26. }
27. }
28.
29. /**
30. * Wrapper around the Android native module.
31. */
32. class AlertAndroid {
33.
34. static alert(
35. title: ?string,
36. message?: ?string,
37. buttons?: Buttons,
38. options?: Options,
39. ): void {
40. var config = {
41. title: title || '',
42. message: message || '',
43. };
44.
45. if (options) {
46. config = {...config, cancelable: options.cancelable};
47. }
48. // At most three buttons (neutral, negative, positive). Ignore rest.
49. // The text 'OK' should be probably localized. iOS Alert does that in native.
50. var validButtons: Buttons = buttons ? buttons.slice(0, 3) : [{text: 'OK'}];
51. var buttonPositive = validButtons.pop();
52. var buttonNegative = validButtons.pop();
53. var buttonNeutral = validButtons.pop();
54. if (buttonNeutral) {
55. config = {...config, buttonNeutral: buttonNeutral.text || '' };
56. }
57. if (buttonNegative) {
58. config = {...config, buttonNegative: buttonNegative.text || '' };
59. }
60. if (buttonPositive) {
61. config = {...config, buttonPositive: buttonPositive.text || '' };
62. }
63. NativeModules.DialogManagerAndroid.showAlert(
64. config,
65. (errorMessage) => console.warn(errorMessage),
66. (action, buttonKey) => {
67. if (action === NativeModules.DialogManagerAndroid.buttonClicked) {
68. if (buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral) {
69. buttonNeutral.onPress && buttonNeutral.onPress();
70. } else if (buttonKey === NativeModules.DialogManagerAndroid.buttonNegative) {
71. buttonNegative.onPress && buttonNegative.onPress();
72. } else if (buttonKey === NativeModules.DialogManagerAndroid.buttonPositive) {
73. buttonPositive.onPress && buttonPositive.onPress();
74. }
75. } else if (action === NativeModules.DialogManagerAndroid.dismissed) {
76. options && options.onDismiss && options.onDismiss();
77. }
78. }
79. );
80. }
81. }
82.
83. module.exports = Alert;
84. ......
此段代码省略了头部的相关内容,在代码的第 16 行通过 Platform 变量判断当前所运行的平台,如果是 iOS 平台,那么就调用 AlertIOS 文件中定义的代码,如果是 Android 平台就调用代码第 32 行定义的 AlertAndroid 用于实现对 Android 原生平台 Alert 的调用,注意代码的第 63 行,是不是和我们实战 React Native 与 Android 平台混合开发的实现一样?所以 React Native 的所有组件与 API 基本都是通过此种方法进行了封装后提供给了开发者,所以我们可以说 iOS 原生平台与 Android 原生平台具备的功能都可以通过封装后在 React Native 框架中使用。
对应的 Android 原生端的实现代码在:https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java。
86. ......
87. @ReactMethod
88. public void showAlert(
89. ReadableMap options,
90. Callback errorCallback,
91. final Callback actionCallback) {
92. final FragmentManagerHelper fragmentManagerHelper = getFragmentManagerHelper();
93. if (fragmentManagerHelper == null) {
94. errorCallback.invoke("Tried to show an alert while not attached to an Activity");
95. return;
96. }
97.
98. final Bundle args = new Bundle();
99. if (options.hasKey(KEY_TITLE)) {
100. args.putString(AlertFragment.ARG_TITLE, options.getString(KEY_TITLE));
101. }
102. if (options.hasKey(KEY_MESSAGE)) {
103. args.putString(AlertFragment.ARG_MESSAGE, options.getString(KEY_MESSAGE));
104. }
105. if (options.hasKey(KEY_BUTTON_POSITIVE)) {
106. args.putString(AlertFragment.ARG_BUTTON_POSITIVE, options.getString(KEY_BUTTON_POSITIVE));
107. }
108. if (options.hasKey(KEY_BUTTON_NEGATIVE)) {
109. args.putString(AlertFragment.ARG_BUTTON_NEGATIVE, options.getString(KEY_BUTTON_NEGATIVE));
110. }
111. if (options.hasKey(KEY_BUTTON_NEUTRAL)) {
112. args.putString(AlertFragment.ARG_BUTTON_NEUTRAL, options.getString(KEY_BUTTON_NEUTRAL));
113. }
114. if (options.hasKey(KEY_ITEMS)) {
115. ReadableArray items = options.getArray(KEY_ITEMS);
116. CharSequence[] itemsArray = new CharSequence[items.size()];
117. for (int i = 0; i < items.size(); i ++) {
118. itemsArray[i] = items.getString(i);
119. }
120. args.putCharSequenceArray(AlertFragment.ARG_ITEMS, itemsArray);
121. }
122. if (options.hasKey(KEY_CANCELABLE)) {
123. args.putBoolean(KEY_CANCELABLE, options.getBoolean(KEY_CANCELABLE));
124. }
125.
126. UiThreadUtil.runOnUiThread(new Runnable() {
127. @Override
128. public void run() {
129. fragmentManagerHelper.showNewAlert(mIsInForeground, args, actionCallback);
130. }
131. });
132.
133. }
134. ......
我们可以通过如上代码看到整个 Android 端的 showAlert 实现完全就是我们平时进行 Android 原生开发的代码实现,而通过 React Native 的封装之后,可以轻松让开发者在前端通过 JavaScript 的代码调用原生平台的方法,还可以直接适配两个平台,这样的框架设计的确有魅力,源码也值得好好阅读。
以上主要是给大家把 React Native 源码的基本结构告诉大家,空闲时间大家可以多去阅读 React Native 的实现源码,希望能对你 React Native 的学习再多一些帮助。
关于源码学习过程中的任何问题都可以在本书的线上资源站点找到我的联系方式和我交流。
15.7 难题解决方法与 Issues 重要作用
任何开发语言的学习,即使相关的书籍讲解得再详细,也不能完全覆盖你在开发过程中遇到的种种问题,所以我们需要掌握一些查找疑难问题的基本方案。
关于大家在学习本书进行 React Native 开发的过程中,有几个建议遵循的原则与查找问题的方案供大家参考。
1. 不要纠结于 React Native 的版本问题
很多时候我们在学习时纠结于 React Native 版本更新后,自己已学习的知识是否会落后,从而频繁地在安装最新版本的 React Native 框架、以及解决新版本与老的学习代码冲突上浪费太多的时间。其实很多的前端框架的更新都比较激进,React 基本实现了两周版本一更新,而每次的版本升级肯定会导致和你既有的项目代码有稍许冲突的地方,而如果你花大量地时间去解决这些冲突没有太大的意义。
所以一般的建议是你固定一个版本的 React Native 进行学习,因为版本的更新一般都很小,你只需要专注于框架的使用学习,尽快通过代码实战掌握框架的基本使用,后期可以认真研究框架的底层实现原理,而后期的版本更新基本都不会离开你已掌握的框架知识,更不会与你理解的实现原理有太大出入。
2. 单个平台进行问题定位
React Native 的开发因为涉及到 iOS 平台与 Android 平台的适配,有时一个问题可能影响到了两个平台的表现,这时应该逐个平台突破,而不是两个平台来一起调试,反而会造成代码的逻辑混乱,如果需要在代码上强制分离逻辑调试,可以通过 Platform 变量判断当前是运行在哪个平台,进而编写特定的平台代码进行分离调试。
3. 善用官方的 Issues
React Native 因为源码就发布在 GitHub 上,所以你可以直接在 GitHub 项目页面上查找开发过程中遇到的问题,在 Issues 页面中已包含了近万个问题,基本上你使用过程中遇到的问题肯定有别人遇到过,所以要学会直接在 Issues 中查找问题的原因以及解决方案,实在找不到解决方案你还可以向 React Native 项目提交 Issue,并可以获得 React Native 开发团队的回复,我想应该没有人比 React Native 开发团队的人更了解 React Native 了吧,不过在提问前最好自己多动手查阅一遍所有的 Issues 是否已包含了你遇到的问题了。
React Native 的官方 Issues 地址为:https://github.com/facebook/react-native/issues,截图如图 A-3 所示。
图 A-3 React Native 官方 Issues 页面
15.8 书籍相关资源列表
本书配套源码的 GitHub 地址
包含书籍中所有标注的完整代码、代码片段等,所有的章节代码都进行了单独文件夹存放,方便查阅,后续关于本书的相关更新也在此 GitHub 中更新。
地址:https://github.com/ParryQiu/ReactNative-Book-DemoReact GitHub
地址:https://github.com/facebook/react/React Native 官网
地址:https://facebook.github.io/react-native/React Native GitHub
地址:https://github.com/facebook/react-nativeawesome-react-native GitHub
地址:https://github.com/jondot/awesome-react-native深入理解 React JS 中的 setState
地址:http://blog.parryqiu.com/2017/12/19/react_set_state_asynchronously/从源码的角度再看 React JS 中的 setState
地址:http://blog.parryqiu.com/2017/12/29/react-state-in-sourcecode/从源码的角度看 React JS 中批量更新 State 的策略(上)
地址:http://blog.parryqiu.com/2018/01/04/2018-01-04/从源码的角度看 React JS 中批量更新 State 的策略(下)
地址:http://blog.parryqiu.com/2018/01/08/2018-01-08/Node.js 官网
地址:https://nodejs.orgnpm 官网
地址:https://www.npmjs.com/Node.js 下载页面
地址:https://nodejs.org/en/download/Homebrew 官网
地址:https://brew.sh/官方 UI 示例 App
地址:https://github.com/facebook/react-native/tree/master/RNTesterreact-native-elements
地址:https://github.com/react-native-training/react-native-elementsreact-native-tab-navigator
地址:https://github.com/happypancake/react-native-tab-navigatorreact-native-navigation
地址:https://github.com/wix/react-native-navigationreact-native-keychain
地址:https://github.com/oblador/react-native-keychainreact-native-sensitive-info
地址:https://github.com/mCodex/react-native-sensitive-inforeact-native-image-picker
地址:https://github.com/react-community/react-native-image-pickerFetch API 文档
地址:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_FetchAwesome React Native
地址:https://github.com/jondot/awesome-react-nativereact-native-open-share
地址:https://github.com/ParryQiu/react-native-open-share新浪微博开放平台
地址:http://open.weibo.com/微信开放平台
地址:https://open.weixin.qq.com/QQ 开放平台
地址:http://open.qq.com/React-Virgin
地址:https://github.com/Trixieapp/react-virginreact-native-pathjs-charts
地址:https://github.com/capitalone/react-native-pathjs-chartsreact-native-gifted-listview
地址:https://github.com/FaridSafi/react-native-gifted-listviewreact-native-vector-icons
地址:https://github.com/oblador/react-native-vector-iconsReact Native metro
地址:https://github.com/facebook/metroGenymotion
地址:https://www.genymotion.com/极光推送官网
地址:https://www.jiguang.cn/jpush-react-native
地址:https://github.com/jpush/jpush-react-native极光推送 iOS 证书设置向导
地址:https://docs.jiguang.cn/jpush/client/iOS/ios_cer_guide/Ape Tools
地址:http://apetools.webprofusion.com/tools/imagegorillaApp 图标生成工具
https://makeappicon.com/
http://ios.hvims.com/
https://romannurik.github.io/AndroidAssetStudio/react-native-code-push
地址:https://github.com/Microsoft/react-native-code-pushReact Native Issues
地址:https://github.com/facebook/react-native/issues以上的所有链接汇总页面
如果你觉得需要查阅以上的链接,手动在浏览器中输入太麻烦,你可以直接访问本书的线上所有链接汇总站点,在此站点中你可以看到以上的所有链接以及链接说明,直接点击即可访问、查阅,希望能帮助大家提高学习效率。
地址:http://rn.parryqiu.com
《React Native 精解与实战》书籍连载「React Native 源码学习方法及其他资源」的更多相关文章
-
《React Native 精解与实战》书籍连载「Android 平台与 React Native 混合开发」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「iOS 平台与 React Native 混合开发」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「配置 iOS 与 Android 开发环境」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「React Native 网络请求与列表绑定」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「React Native 中的生命周期」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「React Native 底层原理」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「Node.js 简介与 React Native 开发环境配置」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
《React Native 精解与实战》书籍连载「React 与 React Native 简介」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
-
[书籍精读]《React Native精解与实战》精读笔记分享
写在前面 书籍介绍:本书由架构师撰写,包含ReactNative框架底层原理,以及与iOS.Android混合开发案例,精选了大量实例代码,方便读者快速学习.主要内容分为两大部分,第1部分" ...
随机推荐
-
如何利用FineReport制作动态树报表
在对数据字段进行分类管理时,利用动态树折叠数据是一个很好的方法,也就是点击数据前面的加号才展开对应下面的数据,如下图.那这样的效果在制作报表时该如何实现呢? 下面以报表工具FineReport为例介绍 ...
-
qml package 的使用
什么时候使用这个.就是多个view使用同一个deleagte的时候. The Package class is used in conjunction with VisualDataModel to ...
-
uva 10107 - What is the Median?
#include <cstdio> #include <iostream> using namespace std; ]; int main() { int i, cur_in ...
-
javascript每日一练(八)——事件三:默认行为
一.阻止默认行为 return false; 自定义右键菜单 <!doctype html> <html> <head> <meta charset=&quo ...
-
[iOS]封装单例类
[iOS]封装单例类 今天在学习iOS的SQLite开发,发现在需要使用SQLite的每个视图中,都需要对数据库进行打开或关闭,觉得挺麻烦的:于是在想能否写个单例类对这些操作进行封(因以前一直在使用D ...
-
mysql5.6默认情况下内存占用太大
下载了mysql5.6.12 ,默认占用内存达400多M, 而原来使用的5.0 只有30M.. 解决方案:调整以下参数----------------performance_schema_max_t ...
-
Javascript高级编程学习笔记(28)—— BOM(2)window对象2
今天讲一下window对象和浏览器导航,弹窗等有关的内容 导航和打开窗口 window.open() 用于导航到某个特定 url 该方法接收四个参数 1.url 2.窗口目标(当页面中有多个框架fra ...
-
python网络爬虫笔记(五)
一.python的类对象的继承 1.所有的父类都是object类,由于类可以起到模块的作用,因此,可以在创建实例的时候,巴西一些认为必须要绑定的属性填写上去,通过定义一个特殊的方法 __init__, ...
-
swift语言混编--语言交互的接口
FFI stands for Foreign Function Interface. A foreign function interface is the popular name for the ...
-
selenium常用命令
openopen(url)- 在浏览器中打开URL,可以接受相对和绝对路径两种形式type type(inputLocator, value)- 模拟人手的输入过程,往指定的input中输入值- 也适 ...