本机反应:开发人员日记

关于如何 创建 此实验项目的 虚构说明

3月15日。

从总部收到备忘录。 他们想在React Native中看到一些东西。 Swift和Java是合格的。 他们正在出路。 我们需要新的热点。 反应本机。 您编写了一些JavaScript和繁荣。 您将获得一个iOS和一个Android应用程序。 您可以立即重新加载代码。 您会得到一个由强大的枪支支持的狂热的开源社区。 脸书 爱彼迎。 乌克兰有人。 大枪。

因此,拉起一些教程,复制并粘贴一些示例代码,然后开始构建一些东西。 随便啦

我是一位本机应用程序开发人员,在Objective-C,Swift,Java甚至Android NDK的多平台C ++代码方面都有丰富的经验。 当HTML5尽其所能地进入应用程序游戏时,我大笑并嘲笑了它徒劳的尝试。 但是React Native引起了一些严重的轰动-我的意思是,乌克兰的一个家伙-而且大佬们想要一些东西。 随便啦 哦,我给你点东西。

3月16日。

我什么都没有

3月17日。

设法使React Native的Hello World应用程序等效于在iOS模拟器和Android模拟器上加载。 但是,这几乎不像按Xcode中的“播放”按钮那样简单。 必须在项目目录的根目录中打开命令行,并为iOS输入一条运行指令,为Android输入一条单独的指令(要求已打开仿真器)。

说到IDE,我决定使用Atom,而Nuclide在其之上。 让我想起了Eclipse时代的Android插件。 那些日子我不想被提醒。 但是,直到发布某种React Native Studio为止,它都必须做。 还安装了Yarn软件包管理器来替换npm,仅因为我认为“ yarn add”和“ yarn remove”是安装第三方React Native组件时要记住的简单易懂的命令。 事实证明,纱线初始化和安装也明显比npm更快。 这绝对至关重要,因为星期五。

npm命令

npm install --save [package]
npm uninstall --save [package]yarn add [package]
yarn remove [package]

3月20日。

就第三方而言,我发现自己拉下来的React Native组件比iOS CocoaPods或Gradle依赖项还多。 对于本机应用程序,我通常只包括AFNetworking / Alamofire来管理iOS中的HTTP请求,仅此而已。 如果项目需要的话,也许是Google Maps SDK。 Android中带有Retrofit的类似故事。 对于其他所有方面,包括UI元素和持久性存储,我能够使用iOS和Android中内置的类来完成大多数事情。

在React Native中,我正在添加一些基本的东西,例如按钮和ListViews! 但是,将每个组件添加到package.json文件后,它们真的很容易开始实现。 使用React的JSX语法,为屏幕布置界面非常简单,特别是如果您已经对使用Android的XML方法进行各种可能的屏幕尺寸设计感到特别满意。 与Xcode的Interface Builder甚至是SnapKit这样的iOS Auto Layout升级相比,这两种解决方案都更容易用于自适应布局。

React JSX

< Button onPress={onButtonPress} title=”Press Me”

/>

< Button android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”@string/press_me” android:onClick=”onButtonPress”

/>

let btn: UI Button = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 50))btn.setTitle(title: “Press Me”, for: .normal)btn.addTarget(self, action: #selector(onButtonPress), forControlEvents: .touchUpInside)

self.view.addSubview(btn)

作为刚从Swift + Java(Swava?Jift?)跳入JavaScript编程的人,我正在学习很多基础知识。 或者,当我编写代码块时,出现红色错误屏幕。 或者当我编写一行代码时。 或者当我写任何东西时。

为什么有些进口商品使用花括号,而另一些却不使用花括号? 事实证明,如果事物(例如,组件,函数,常量)是其模块的默认导出,则不需要括号。 花括号用于所有其他非默认导出。

import mainDoer from './Doers'import { thingDoer } from './Doers'export default function mainDoer() { code }

export function thingDoer() { code }

箭头语法有什么用?

someNumberArray.map(item => item + 1); // Add 1 to each number in the array

好吧,它只是这种逻辑编写方式的一种较旧的替代方法:

someNumberArray.map(function(item) { return item + 1;})

好吧,那么这些省略号又如何呢? 实际上,有不同的种类。 有一种传播语法采用单个元素,并且有望扩展为多个参数或元素。 因此,而不是使用无用null的代码:

function doThinger(a, b, c) { code };var args = [0, 1, 2];doThinger.apply(null, args);function doThinger(a, b, c) { code };var args = [0, 1, 2];doThinger(...args);

其余运算符与散布语法不同,其余运算符不是将数组扩展为其元素,而是将多个项目压缩为一个。

var [dope, ...wack] = [1, 2, 3, 4, 5]; // wack = [2, 3, 4, 5]

所以这一切都很好,很有趣。 但是随着我不断写越来越多的JavaScript,这种语言显示出自己……虚弱? 在某种意义上说,Swift和Java对于分号的使用具有“强大”的规则是弱的,但是实际上它们并不是您必须记住或考虑的规则,而实际上并不是您编写的部分代码,因为它具有完整,明确的意义。 JavaScript继续就分号的使用争论不休,而尾随逗号是可选的(虽然在JSON中是不允许的),这让我想念本机应用程序语言,您不必担心这些东西,而只关注解决问题。

3月21日。

与其最终以教程和代码示例漫无目的地徘徊在React Native世界上,倒不如最终有一个目标可以集中精力并朝着这个目标努力。 决定构建一个使用Google Places API中的兴趣点标记填充地图的应用。 轻触特定位置标记后,将在缩略图的GridView中获取该位置的Instagram照片。 这里有许多概念在起作用:HTTP请求,JSON解析,图像下载和缓存,地图和标记以及UI的乐趣。

下拉了Airbnb的react-native-maps组件。 显然,Airbnb的实现已超出了原始内置MapView组件,并且在1月份中断了对前者的支持,并正式推荐使用第三方地图。 那是一些严肃的开源社区力量。 似乎也是一个不错的决定,因为放入Airbnb JSX(以及Google Maps API密钥)后,iOS模拟器中的功能Apple Maps视图和Android模拟器中的Google Maps视图的运行速度比我快得多。每个平台一次原生添加地图。

为了用真实位置数据的标记填充地图,我使用了React Native的Fetch API。 通过为Fetch提供Google Places URL,我得到了一个JSON响应,该响应很容易解析为对象或多维数组。 我还能够快速添加纱线并利用一个名为traverse的第三方库来评估响应中的每个键值对,同时考虑其在结构中的深度。 对于我来说,这个库已经有将近4年没有更新,但是开箱即用的功能对我来说似乎是不可思议的,而且我不知道iOS或Android库是否会发生这种情况。

从JSON响应中提取相关地理位置数据后的下一步是创建模型(与本机模型相同),以便我们可以构建一系列标记以放置在地图上。 也许就反应式编程而言,这不应该是下一步吗? 我应该遵循一种适当的功能方法吗? 那好吧。 对我来说很有道理。 我之所以表示担忧,只是因为在React Native中创建模型没有任何标准或许多示例可循,而iOS和Android具有相当普遍的模式,因为模型是MVC的很大一部分。 甚至有三分之一的首字母缩写!

我这样编码了MarkerData模型:

export default class MarkerData { constructor(locationId) { this._locationId = locationId; } getLocationId() { return this._locationId; } set name(name) { this._name = name; } get name() { return this._name; } set latitude(latitude) { this._latitude = latitude; } get latitude() { return this._latitude; } … // NOT CODE. Just saying etc. and so on and so forth...

创建此模型的对象将如下所示:

for (var i = 0; i var markerData = new MarkerData(idArray[i]); markerData.name = nameArray[i]; markerData.latitude = latArray[i]; markerData.longitude = lngArray[i]; markers.push(markerData);

}

然后从模型创建地图标记可能如下:

getFeedMarkers() { return this.props.feed.map( (markerData, i) =>

key={ i } title={ markerData.name } coordinate={ {latitude: markerData.latitude, longitude: markerData.longitude} }>

{ markerData.name }

);

}

3月22日。

从传统的Swift和Android Java迁移到React Native不仅需要使用其他语言和工具。 我还必须尝试以反应方式解决问题,而不是习惯于以原生方式解决问题。 例如,在创建MarkerData对象数组之后,我的本机下一步将是遍历该数组,并且在每次迭代中,直接访问map对象以调用其函数以添加单个Google标记或MapKit注释。 如果我们的一组标记发生了变化(例如,当用户在地图上移动时),我们必须从地图对象中清除上一组标记,然后再次运行循环。 永远不要过多考虑这个命令性的,面向对象的过程的乏味,因为,这就是事情的本质。

但是,在反应式编程中,我们可以用更少的精力和更自然的思维方式来完成相同的结果(在此示例中,将当前标记集放置在地图视图上)。 如果我们只是告诉地图视图怎么办?“嘿,这是地图标记的数组。 如果要在屏幕上渲染自己,则只需显示给定时间数组中的标记即可。 不要懒惰,等我将标记逐个递给您-随着数组的变化而做出反应。”似乎更自然一点吗? 除了与代码块交谈。

这种观念上的转变也帮助我决定在应用程序中使用Redux。 任何新的React Native开发人员注定会在阅读越来越多的文章和教程时看到这个词。 我想如果我想要完整的React Native经验,我需要收集整个集合。 工具。 我很高兴自己做到了。 对于更新地图上标记的任务,这完全是过大了。 但是,我得到的不只是这些。 经历了使用Redux的学习痛苦,迫使我改变了思维方式,以变得更加被动。

第一步:为MapView组件提供一个数组,使用该数组进行位置标记。 实际上,我已经讨论过这一部分-它是昨天的getFeedMarkers()函数。 Redux使您可以对要观察的有状态事物使用道具。 在前面的示例中,它是“ this.props.feed”属性,在该属性上运行了一个地图函数,该函数描述了如何为数组中的每个位置绘制标记。

每当获得新的位置集时,我们如何更新此地理位置提要阵列? 这就是过量使用的部分所在。在Redux中,我们可以将feed设为全局应用程序状态(称为store)的一部分 。 您不会立即用新值写入该数组。 您分派了一个动作 ,该动作几乎说:“嘿,我刚成功收到了地理位置提要,就在这里。”分派的动作将被称为reducer的东西捕获,该东西执行必要的逻辑以更新Redux状态。 此操作是从成功的访存调用中分派的。

fetch(url).then((response) => { if (!response.isOk) { throw Error(response.statusText); } return response;}).then(response => response.json()) // Extract the JSON body (if valid).then(feed => { dispatch(feedsFetchSuccess(feed)); // dispatch is a Redux keyword

})

Redux将要分派的动作只是:

export function feedsFetchSuccess(feed) { return { type: FEEDS_FETCH_SUCCESS, feed // ES6 shorthand for “feed: feed” }

}

因此,当我们的API提取接收到JSON响应时,我们告诉Redux将操作分发给商店,并随其携带地理定位提要作为有效负载。 编程为拦截具有该名称的操作的reducer会将现有商店替换为包含Feed的新商店。 函数式编程的主要宗旨之一是不变性,因此Redux需要一个新商店,而不是更新当前商店。

export function feeds(state = [], action) { // Initialize the state to an empty array switch (action.type) { case CLEAR_FEED: // “Clear” the feed by replacing the state with an empty array return []; case FEEDS_FETCH_SUCCESS: var newState = Object.assign([], state); // Create a new state from the old state newState.push({ action.feed }); // Add to the state the feed attached to the action return newState; default: return state; }

}

是的,这是一种更新地理位置提要的超级回旋方式,就像在Swava中清除数组并向其中添加项目一样简单。 但是,当来自某个世界的人开始深入研究反应式编程时,实施Redux迫使我遵守一些函数式编程的原则:不可变的数据结构和纯函数(在输入相同的情况下,总是返回相同的结果)输出)。

3月23日。

是时候显示用户点击的Google地方信息位置的Instagram照片了。 是时候添加另一个第三方组件了。 最后是RNFetchBlob,它与Fetch具有几乎相同的API。 RNFetchBlob还具有通用的目录结构,该结构抽象出允许您的应用程序将文件放入其中的沙盒目录,这在iOS和Android中有所不同。 无论如何,每次下载图像时,我们都会再次通过Redux流程,将图像的文件路径添加到包含所选位置的图像的所有文件路径的数组中。 当在屏幕上点击一个新的位置标记时,将清除并重新填充此数组。

在这一点上,想到了将此映射应用程序想像成具有两个通道的DJ混音器的想法。 第一频道是使用标记填充地图的位置信息。 第二频道是第一频道中所选位置的一组丰富数据-在本例中为Instagram图片。 最后,为应用命名。 地图调音台!

另一个终于。 实际的用户界面内容! 我们已经具备了基本的功能,并且认为在屏幕上实际看到其中的一些会很不错。 还指出,我现在不想花太多时间来构建自定义UI组件,并希望在那里的某个人已经做出了相当大的努力,以创建一个即插即用按钮和文本标签之类的库。 为运行应用程序的平台(iOS或Android)自动以本地样式设置的UI元素。 NativeBase做得很好,甚至使用简单的XML简化了导航栏和主布局之间的元素分离:

render() { return (

{/* Anything within Header is placed in the nav bar! */}