最近踩了一些坑,不吐不快,原文在自己 blog 上: https://pc9527.github.io/2018/05/04/six-month-and-sixteen-days.html
选择 React Native 的开发者,“性价比”肯定是主要原因。选型时发现虽然分了 iOS 和 android 两个视图,但 ListView/Navigation 啥的似乎都是通用的嘛!跑 demo 也没啥问题,看来写一遍代码就可以适配俩平台了,赶紧入坑吧!
“一入侯门深似海”真是放之四海而皆准,一旦进入具体功能开发,需要用到各控件比如 toast/picker/segment/FAB 的时候,发现还真没有跨平台的,能用的就文档首页列出来那几个。而且我就需要一个统一通用布局的
<Container>
<Header />
<Content />
<Footer />
</Container>
也没有。
这时“社区活跃”的优点就体现出来了,github 上俩最高 star 的 react-native-elements 和 nativebase 都是为了让开发者只写一遍视图代码而生的工具。经过试用,前者偏重于小而美的 UI,比如按钮 /search bar ;后者则提供了整体页面布局的容器如上面提到的 Container/Header/Content 和基于 flexbox 的 Grid/Row/Col 等等,这俩结合起来基本够用。
nativebase 是一个印度软件外包服务商的产品,因为 facebook 团队迭代太快,所以不太能跟得上节奏,虽然 nativebase 的更新在社区里已经很算活跃了,但还是落后 React Native 主版本 3 个月以上。体现在工程上,就是基于 nativebase 写一遍能用于 iOS 和 android 的代码,不能第一时间获得 React Native 的 bugfix 和性能提升以及新功能,怎么取舍看需求了。
Facebook 那么有钱,能不能像 Flutter 那样把 UI 层给趟成一条道啊?
Facebook 出的产品,精神上都继承了那句“ Move fast and break things ”,move fast 是好的,只是不知道 break 了谁的 things ——一般都是用户的,毕竟 move fast 的总占上风。所以要想不被带到沟里,得比 facebook 团队还要快。
虽然 facebook 对 React Native 的更新很快,但更新的内容并不一定符合我的需求:新功能开发走向和 roadmap 制定源于社区投票和 facebook 第一方应用的需求,根据 0.55 版以前的 changelog 来看,更新的重点在于:适配更多的新设备,支持更多的原生功能,使 React Native 本身更易用。对于至今还没发布 1.0 版的开发工具来说,这个发展策略很正确,1.0 发布时肯定是很好很强大的产品。
但性能优化就靠后了,很难想象经历了 40 多个版本的发布直到 0.43 版才推出新的 FlatList,代替会渲染全部元素的 ListView 控件。而且即便是基于虚拟渲染窗口 VirtualizedList 的 FlatList 和 SectionList,性能依然不能令人满意,估计 facebook 的测试数据不到 1000 条?后来几经调试,改小了 windowSize 才勉强把主 UI 线程跑到了 50 帧以上。
这里推荐一下 react-native-largelist,采用 lazy 渲染,但凡是不太需要频繁刷新的超长列表(比如外卖菜单,每个 section 和 section 里的 element 起码一个工作日里不太可能会增减),perf monitor 里双 60 帧毫无压力。
就 iOS 版的 React Native 来说,从 js context 映射到 main queue 是一条不可逾越的性能沟壑。但现在最新的 0.55 已经开始 Animated tracking 已经可以 useNativeDriver 来驱动,即便 js 线程停了,ui 还是丝滑得很。希望这种做法早日能扩展到其他控件上——参见把鼠标驱动放到系统 ring0 层的 Windows ——就算死机了,我的鼠标指针还能动!
React Native 本身的功能很简单纯粹,就是一个虚拟 dom 渲染引擎,把代码里的<view>等标签映射到虚拟 dom 树之后,再转换成 UIView 等 native 的控件(同理 react 是把 jsx 里的 div 渲染成浏览器里的 div )。但开发一个 app 需要的远不止于此:需要进行数据状态管理,导航控制,表单处理,数据持久化......
React Native 对功能整合的做法是典型的 Unix 方式:由每个工具提供功能和接口,用户把所有工具串联起来完成业务逻辑。当初弃了 Angular 入坑 React Native 的最后一根稻草就是这很 Unix 很自由,和我这后端出身的太衬了!
充分行使了 React Native 给予的自由之后,才发现是有代价的。比如数据状态管理,官方的方案是 flux,社区最流行 redux,mobx 最酷炫,选择相对最安全的 redux 了吧,还跟 immutable.js 不兼容(在做网页版 dashboard 的时候,redux 和导航用的 react-router 还有 3.x - 4.x 的破坏性版本更新,用最新的吧,版本还是 alpha 的,说多了都是泪)。
到了 action 管理,又有 thunk 和 saga 让你左右为难:thunk 简单明了,但不停 dispatch 失之繁琐; saga 一个异步函数收工,但需要精心设计......
都是成熟的工具库,完成本领域的工作毫无压力,但在开发者整体认知能力一定的情况下,把这些集成起来配合工作不出幺蛾子的可能性可以忽略不计——而且各个组件的文档通常是很少会出现和其他库集成的例子—— api 变得太快,我自己的还可以控制,引用别人的回头改了这 sample 就不能跑了啊喂!
加上我又是 Anders 三十年老粉,Typescript 是一定要用的,但我能说微软 github 上那个 react 的 starter 涵盖了一个 app 的 30%日常功能都不到吗?这是逼着人举一反三哪!
有些库(对就是你 nativebase )的功能代码 js 更新了,但是对应的 Typescript definition 还是旧的,编辑器很尽责地告诉你这里 type 不对,不能 assign,还好 Typescript 的开放式 interface 声明估计就是为这个而生的,可解燃眉之急(其实是强迫症,见不得报错)。
x 轴是待开发 Feature,y 轴是各个开源库,z 轴是 Typescript/ES6/Flow,所幸编辑器 Visual Source Code 很好使,不然这一团混沌连个抓手的都没有啊!
作为前端开发者,有什么比改完详细页里按钮颜色还要重新编译代码,再从索引页点进去才能看到效果更影响开发速度的呢?
所以用 Ionic 1/AngularJS 的时候能改完 js 就快速刷新已经很幸福了,React Native 更进了一步:app 的 state 都不变,只刷新刚改的那个组件。这个特性在调整 UI 阶段节省了我大量时间——当然要是改了 dataStore 相关的 reducer 函数还是会要求整体刷新。
相信这个特性也是很多开发者不愿放弃 React Native 的主要原因。
虽然会碰上各种问题,但只要社区够大够活跃,总能提供解决方案——上述所有问题,都有人踩过坑,所以 SO 和 github 上都有解法。
至于没人碰到过的问题——恭喜你,已经进入研发的前沿领域了!
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.