Dropanon

为什么我构建一个React Native App

Dropanon出生于我寻找解决两个目标的方法时:

  1. 在React Native中从头开始构建一个应用程序
  2. 通过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处理)。 从启动开始的基本应用程序流程如下:

  1. 初始化应用程序和加载视图。 这在顶级React组件App.js中处理。 在componentDidMount() ,这里发生了很多事情,例如检查用户是否已入职或是否已授予正确的权限(在使用应用程序时的位置)。 所有的Reflux商店也在此处初始化,并附加了侦听器。
  2. 如果缺少权限,用户尚未注册或发生其他问题,我们将适当处理。
  3. App.js初始化的Reflux商店开始处理各自的任务。 这些在逻辑上分为: ErrorStoreFirebaseStoreGeoStoreTimerStore

ErrorStore.js

ErrorStore负责错误。 任何捕获到的错误都将传递给它,然后传递回App.js ,然后在顶部显示一个错误栏,告诉用户出了什么问题。 可以通过点击横幅关闭横幅。

FirebaseStore.js

所有滴都保存到Firebase的实时数据库之一并从其中读取。 Firebase允许我们省去编写自己的后端的工作,很快我们就可以运行并运行原型。 我们遇到了一些挑战,但总的来说,我认为使用Firebase比使用自己的后端要快(https://dropanon.com也托管在Firebase上)。

FirebaseStore初始化Firebase实例,并使用其signInAnonymously()函数创建用户(具有读取/写入权限)。 所有数据库交互都通过此存储。 它们如下:

  1. onFlagDrop() —用户已标记丢弃。 FirebaseStore将按postId查找帖子,并将其flagged属性设置为true。 如果用户选择从设置菜单中隐藏标记的液滴,则这些液滴将不再显示给他们。
  2. onFetchFeed() —使用坐标参数,并使用GeoFire地理查询来获取当前位置的正确下落。 然后将返回的drop存储到以下dropsToDisplaydropsToDisplay if: distance <= dropRadiusdropsToMap if distance <= 500
  3. 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(() => {...});