Dropanon
为什么我构建一个React Native App
Dropanon出生于我寻找解决两个目标的方法时:
- 在React Native中从头开始构建一个应用程序
- 通过Apple App Store提交过程获取应用
该产品本身是出于我对在线匿名性的个人爱好而诞生的,而我的联合创始人则非常讨厌别人发表Yelp评论来建立自己的在线品牌。
什么是Dropanon?
Dropanon是一个基于位置的匿名消息传递应用程序,当前可在iOS应用商店(Android即将推出)上使用。 用户可以将单词,表情符号或链接放在他们的位置。 每个液滴的半径为75米,只能在该半径范围内读取。 认为它像涂鸦。
液滴在地图视图上可视化,并在提要/列表视图中读取。 该地图将仅可视化距用户最多500米的跌落。 施加此限制是为了限制客户端需要发出的请求的数量,并鼓励用户四处走走和探索。
每滴都是匿名的。 存储的唯一标识符是RFC4122 v1唯一用户ID(使用React Native UUID1)。 此UUID仅用于允许用户标记或阻止其他用户(这是App Store的要求)。
当前,液滴将永远存在并按时间顺序显示给用户。 我们已经收到的一些反馈是使滴剂暂时消失-在一定时间,数分钟或数天后使它们消失。 这是我们将来可能会做的事情,但就目前而言,您的贡献将继续存在。
怎么样
Dropanon使用React Native和Reflux构建。 持久性由Firebase处理(对于地理查询,则由GeoFire处理)。 从启动开始的基本应用程序流程如下:
- 初始化应用程序和加载视图。 这在顶级React组件
App.js
中处理。 在componentDidMount()
,这里发生了很多事情,例如检查用户是否已入职或是否已授予正确的权限(在使用应用程序时的位置)。 所有的Reflux商店也在此处初始化,并附加了侦听器。 - 如果缺少权限,用户尚未注册或发生其他问题,我们将适当处理。
- 由
App.js
初始化的Reflux商店开始处理各自的任务。 这些在逻辑上分为:ErrorStore
,FirebaseStore
,GeoStore
和TimerStore
。
ErrorStore.js
ErrorStore负责错误。 任何捕获到的错误都将传递给它,然后传递回App.js
,然后在顶部显示一个错误栏,告诉用户出了什么问题。 可以通过点击横幅关闭横幅。
FirebaseStore.js
所有滴都保存到Firebase的实时数据库之一并从其中读取。 Firebase允许我们省去编写自己的后端的工作,很快我们就可以运行并运行原型。 我们遇到了一些挑战,但总的来说,我认为使用Firebase比使用自己的后端要快(https://dropanon.com也托管在Firebase上)。
FirebaseStore初始化Firebase实例,并使用其signInAnonymously()
函数创建用户(具有读取/写入权限)。 所有数据库交互都通过此存储。 它们如下:
-
onFlagDrop()
—用户已标记丢弃。 FirebaseStore将按postId
查找帖子,并将其flagged
属性设置为true。 如果用户选择从设置菜单中隐藏标记的液滴,则这些液滴将不再显示给他们。 -
onFetchFeed()
—使用坐标参数,并使用GeoFire地理查询来获取当前位置的正确下落。 然后将返回的drop存储到以下dropsToDisplay
:dropsToDisplay
if:distance <= dropRadius
而dropsToMap
ifdistance <= 500
-
onDropSubmit()
—放置一个放置对象,进行一些检查以确保其全部存在并将其推入数据库。
FirebaseStore还执行其他一些操作,例如保存在设备上的设置和/或获取权限设置。
GeoStore.js
GeoStore处理所有与地理位置相关的任务。 在初始化时,将获取当前位置并将其传递给App.js
然后为侦听器附加一个10米的distanceFilter
,因此,如果当前位置和最后一个位置之间的距离大于10米,则可以获取最新位置。
TimerStore.js
TimerStore用于跟踪时间。 我们限制每位用户每5分钟3滴。 这里没有什么花哨的东西。
挑战性
- 在传统意义上,GeoFire不允许您按位置查询。 相反,它会在
key_entered
上触发事件。 这意味着我们不能在服务器上限制或分页结果,而必须在客户端上执行。 目前,这很好,因为每个设备下载的Drop总数相对较小,但是如果使用率增加,将来可能会成为一个问题。 - React Native调试可能很困难和/或很耗时。
- JavaScript的单线程性质可能会导致性能问题。 我们在这里还没有遇到任何严重的问题,使用
Interactionmanager.runAfterInteractions(() => {...});
缓解大多数问题Interactionmanager.runAfterInteractions(() => {...});