从 2024 年 7 月开始,我一直都致力于 react native 开发,9 月入手一个正式的业务线 app 使用 react native 开发,直至年底,此文有感而发,有所不足,望多体谅
由于是重写已有的 native app,个人在写 rn 代码时参考了很多 na 的代码,在体验各端代码的差异性。同时也和各方合作,其中遇到很多困难,不限于沟通合作,异常测试,问题复现。不仅于此,看的代码越多,越能体感好代码的难能可贵。回头复盘自己的代码,也是感触良多,在当时迫于工期紧张而写出的代码,现在来看真是一坨 shit。
以下会从几方面来复盘自己这几个月做 rn 跨端 app 的感受,从各端代码分析,去思考怎么写出好代码,怎么去更好地完成合作:
- 弹窗与多弹窗管理
- 页面流转与路由守卫
- 团队合作与依赖
一、弹窗与多弹窗管理
前端在弹窗编写上一般都要预埋弹窗或弹窗容器,不能直接弹出,比较好的实现可以参考 vue-final-modal。但还是需要预埋弹窗容器,去定位需要放置并展示弹窗。
像 iOS 可以将自定义 view (弹窗) 盖在当前 vc 上,android 可以拿到当前 activity 将 fragment 或 view 弹出,harmony 上兼容了另一个写法,以类似路由的方式盖上一个 page,但不影响生命周期,在这个 page 上操作弹窗 modal。
na 的写法,个人认为更加简单,不用想前端一样需要预埋节点,因为 na 能够直接拿到对应的节点。
尽管如此,使用了预埋的办法,那有没有什么更加直观一点的操作呢。在 rn 项目,我基于 react-native-root-siblings 这个库去实现我的弹窗管理,基于这个库实现页面弹窗和全局弹窗 (使用具名容器,而非默认查找的容器)的效果,我实现了一个和这个近似的类:
class Modal {
private rootContainerName: string;
private config: any;
private template: ComponentType<any>;
private modal: RootSiblingsManager | null = null;
private static modalArr: Array<RootSiblingsManager> = [];
constructor() {}
public setTemplate() {}
public setConfig() {}
public setRootContainerName() {}
public setMountCall() {}
public setBeforeUnMountCall () {}
public show() {}
public update() {}
public close() {}
public closeAll() {}
}
基于这个类还可以实现一个 ModalFactory
:
class ModalFactory {
private static modalTemplate = new Map<ModalType, new () => Modal>();
public static generate<T extends ModalType>(type: T) {
const new_modal = ModalFactory.modalTemplate.get()
if (!new_modal) {
throw new Error();
}
return new new_modal() as ModalClass[T]
}
}
通过这个类工厂去管理不同的弹窗模版,比如 popup
和 alert
,弹窗模版基于 Modal
去扩展,可以实现一些多弹窗一起展示或队列管控的效果。目前到这里,个人对于这个弹窗模版还是比较满意的。
但老实说,必须要预埋的操作还是让人讨厌。同时,为了确保弹窗的完全销毁,还必须在弹窗的生命周期里添加兜底销毁方法。老实说,本来我是想用弱引用优化,但发现这弱引用完全不好使,或者说是在实例所在的函数未销毁,导致引用还在未释放。总而言之,会有很多局限的地方。
业务与通用组件
接下来就是弹窗模版的事了。一般而言,在一个 app 中,弹窗的整体风格和样式都是统一的,那么做出弹窗模版就是一件很有必要的事情。但在这一步,很容易陷入 为当前业务所使用的弹窗
这一陷阱。让做出的弹窗模版仅能在当前业务使用。
弹窗一般分为两个部分,一个是进出的动画,两一个是基本内容样式。尽管在一般业务中,样式和动画深度绑定,但我认为依然应当将样式和动画分开,以实现不同模块的复用,就像这样:
<AnimationPopup>
<A_Content></A_Content>
</AnimationPopup>
<AnimationPopup>
<B_Content></B_Content>
</AnimationPopup>
动画添加基本的可配置项,里面的内容模版可供替换,以此来组成基本的弹窗模版。
但实际业务开发中,我是在开发后期想到这一步的,如果要进行更换适配,这又是一个很大的工作量,同时也有一定的风险。这又陷入了一个瓶颈。
二、页面流转与路由守卫
在前端方面,火热的框架 react
或 vue
都有一套基本的路由库,像是 react-router ,vue-router,坦白说,我更喜欢 vue-router
的写法和操作,react-router
的使用多少有点恶心。在路由守卫这方面表现的更是如此。
但不管怎样,在接触了 na 的路由栈管理之后,我都觉得两者或多或少都有些不足,比不上 na 的,毕竟他是基于系统的适配。
在 react native
,一般使用这个库—— react-navigation 去做路由栈处理。但这个库缺陷也很大,尤其是在这个纯度不够 (na 中套 rn ) 的 app 中,使用起来就显得有些不够看,必须 na 通过 turbomodule 或 emitter 来不吃缺失的功能。
路由守卫
路由守卫是路由管理中不可或缺的一块,用于拦截和重定向等功能。在 react-navigtaion
并不能很好地做到,使用自己自定义的路由视图,包装 router
,在 router
中拦截跳转前还行。
在进行 router
的开发中,路由守卫在开发过程遇到了几个之前没考虑到问题,比如路由拦截中的路由跳转还走不走路由拦截,在这个 app 还需要区分全局拦截和局部拦截吗?这里再包一层 rourer
自定义有意义吗?
首先,参考其他一些成熟路由守卫方案,我觉得拦截之后重定义在拦截这个可以接受,因为跳转路由本就该拦截,但需要使用方来避免无限循环;其次,这个 rn app 是单纯的 na 容器里的一个小 app,在他的 rn 容器内部,我认为这就是 rn 的全局拦截,在这里讨论全局拦截还是局部拦截没有意义,再包一层自定义 router
更显得要点多余,说是画蛇添足都不为过。
另外,这里想提一下 na 的路由拦截管理。na 会提供一个注册器,可以是协议,也可以是装饰器,供子业务线注册局部拦截,子业务线的路由拦截还需提供注册的 scheme
。然后在拦截时,去遍历各个业务线的拦截器,防止各业务线 scheme
重复注册,同时通过对应拦截器的拦截方法。对于复杂应用来说,不得不承认,这是套很完善的路由拦截系统,至少相比我现在使用的 rn 路由拦截完善的多。
引擎复用
坦白来讲,这个 na 和 rn 混合的 app 开发,复杂度很容易就上去了,尤其是在迁移过程中,不得不考虑多方面的因素。最直观的表现为 na 的路由跳转 rn 会重新开启一个 js 线程,这不仅加大了系统的负担,也会使一些单例重复,导致一些意料之外的错误。
引擎复用是其中一个解决方案。虽然也可以考虑从路由方面拦截 na 方面拦截的操作,通过 emitter
抛给 rn 的路由栈处理,但我个人认为这只是缓兵之计罢了。就像我上面提到的 na 路由拦截,各个子业务都有对应的拦截器,如果 rn 实践很好,还需要保留原 na 业务线的代码吗?
对于引擎复用来说,本人并没有太多见解,可以参考下这篇文章:对ReactNative引擎进行持有/复用/与限制等讨论。
三、团队合作与依赖
不仅仅从代码开发的角度,这里更想讨论下不同团队之间的合作。对于我所在的 rn 直接使用开发方来说,我就是依赖其他团队的。依赖项有了,遇到问题就要去 push 对方,同时自己还要去排查问题,将问题分派给依赖方去解决;不仅如此,业务方的开发很容易被依赖方给阻塞,导致业务方需要给依赖方兜底。如果依赖方摆烂,业务方那又更是恶心了。
为了给业务方兜底,所写出的代码更是”技术壁垒”。如果依赖方写出的代码还不行,建议直接爆了。在这个业务线 app 开发,笔者深有感触,在爆了和努力之间直接摆烂,受够依赖方的折磨,推又推不动,bug 还得挂我名下。依赖方提供的 sdk 或 lib 又是 shit 中的 shit,完全不通用,但又不是完全为当前业务适配,总之半斤八两。搞得我写代码都不自信了,好代码是真的难能可贵,团队协作是真的想 peach。
坦白来讲,就这几个月的 rn 开发,个人是被依赖方深深恶心到了,目前我也没有好的解决办法,因为这种垃圾依赖,每天写个代码都不安心。这篇文章—— 入行 14 年,我还是觉得编程很难的话不是没有道理。
这几个月,对于读者来说,个人复盘,自己提升了哪些东西:
- 屎山的评鉴经验
- 团队合作初探,如何优化协作暂时没有解决方案
- 软件的工程思维
- 还有就是 react native 的开发经验吧,对 iOS 和 Android 开发也有粗浅的认知。
到头来还是在发牢骚,如上所说真的有所成长吗? 今年一本书没读,新技术没接触,真是感慨呀? 迈入正式工作的第一年,不知前路如何?
本来还想吐槽一下 react
开发相关的,和 na 对比了一下,感觉这种前端框架所给予的东西,相比 na 来说,缺陷是真的有点大,不过,换种角度来说,本身 react
就是面向于 web 的,赛道不合,也没什么好比的。
这种探讨,笔者更多是吐槽吧,但也反思自己吧,不能光是吐槽,也应该学习到一些皮毛。
粗浅给自己结个尾吧?立一下来日的 flag,希望自己不再拘泥于基本的业务吧,多学下优秀的第三库的代码和设计理念,多读几本书,希望还能再捡起那把吉他。
对不成熟的自己多些包容吧,写给未来。