如果你应用 Taro 开发感觉 Bug 少,那阐明你的 React 代码写得很标准。 -- Taro团队
趁前段时间做基于taro2的微店铺以及taro2升taro3的我的项目教训,简略介绍Taro2跟Taro3的各自的优缺点以及理论应用场景下的语法区别,并分享Taro3降级中和应用中的踩坑点。
举荐浏览
小程序跨端框架开发的摸索与实际
Taro1/2
Taro3之前的整体架构能够看成两局部:编译时和运行时。这里解释一下两者的用处:
编译时:
通过对⽤户的 React 代码进⾏编译来转化代码语法,如jsx
转小程序xml
等,甚至转换成各个平台(抖音小程序、微信小程序、H5等等)都能够运⾏的代码。编译时工作流程次要是通过babel
将 Taro 代码解析成形象语法树,而后操作语法树生成指标平台的代码,也就是parse -> replace -> generate
这样一个工作流程。
以build:weapp
编译微信小程序端为例:
render() { return ( <View> { dataList.map((data, index) => (<Text key={index}>{data.title}</Text>)) } </View> )}
通过babel转换后:
<view wx:for="{{dataList}}" wx:for-item="data" wx:for-index="index"> <text>{data.title}</text></view>
咱们都晓得 JSX 是一个 JavaScript 的语法扩大,它的写法变幻无穷,非常灵便。这里咱们是采纳 穷举 的形式对 JSX 可能的写法进行了一一适配,这一部分工作量很大,实际上 Taro 有大量的 Commit 都是为了更欠缺的反对 JSX 的各种写法。
这是摘自官网对taro2编译时的一句形容,因为应用穷举的适配形式,势必会造成jsx的各种各样的奇怪的bug产生和各种开发时的限度。
运行时
能够晓得的是,咱们开发taro我的项目时,援用的是taro库上面的api和组件,调用相似微信原生的api,如: wx.getSettings
,在taro外面须要从 @taro/taro
援用,而后调用 Taro.getSettings
,组件则是通过@taro/components
援用。这是因为Taro制订了一套运行时的规范组件库和api,通过对原生api进行拓展和配合编译时曾经抹平了状态、事件绑定、页面配置和生命周期等的差别,实现了框架的适配工作。具体点形容:
编译后的taro代码实现了 BaseComponent
和 createComponent
,BaseComponent
的作用次要是重写了react外面的render、setState等外围代码,createComponent
次要作用是调用 Component()
构建页面,解决以下等对接工作实现适配:
- 将组件的 state 对应为小程序组件配置对象的 data
- 将组件的生命周期对应为小程序组件的生命周期
- 将组件的事件处理函数对应为小程序的事件处理函数
- ...
简略来说就是先将代码编译成各个平台结构化语言的代码,而后通过适配器模式等等办法适配到各个平台可能让之运行起来,整个Taro2的架构编译时做的工作占次要局部,运行时工作量较小。
总结
- 重编译时,轻运行时:这从两边代码行数的比照就可见一斑。
- 编译后代码与 React 无关:Taro 只是在开发时遵循了 React 的语法。
- 间接应用 Babel 进行编译:这也导致在工程化和插件方面的羸弱。
Taro3
Taro3能够大抵了解为解释型架构,这个工作就次要是在运行时"对代码进行解释",怎么了解呢?降级为Taro后你能够发现package.json
文件外面多了个(当然不止这一个)@taro/runtime
的依赖,关上包所在目录:
惊奇的发现了咱们在web中才会有的bom
跟dom
相干的关键字,原来Taro3本人实现了一套相似浏览器的BOM/DOM那一套API,通过webpack的plugin注入到小程序的逻辑层,打包编译后,你最终的代码都是基于BOM/DOM这几个API来实现你的具体性能,比方:不论什么平台,都有本人一套元素dom的规定,都有各自平台的相似bom的全局api规定,Taro3做的就是整合这些厂家的规定封装为相似BOM/DOM的思维去用,也就是说,我不论你开发时用的什么框架,我只有保障你运行时能帮你适配到各个平台即可。
这样做的最直观的益处就是后面说到的,不再受限制与框架自身了,实践上来说,Taro不仅能够反对Vue和React,也能用jquery、Angular等等的库进行跨端开发。站在React的使用者角度:通过taro2和taro3两个我的项目开发教训来说还有一点最直观的感触,taro3中写JSX
更加难受了!其实就更加敌对的反对JSX
这一点,应该是牵强附会的,因为taro的架构其实就是有限靠近于React的开发体验,适配的工作是通过运行时的BOM/DOM去实现的,而不是像之前版本一样,通过穷举 的形式对 JSX 的写法进行适配。
有个关键点:既然Taro3本人实现了BOM/DOM这一套api,而react的中的渲染器,如react-dom
中调用的是浏览器的BOM/DOM的api,那taro必定会有本人一套渲染器来链接react的协调器(reconciler,diff算法所在阶段)和taro-runtime
的 BOM/DOM api。源码门路:@tarojs/react
,description外面的形容如下:"like react-dom, but for mini apps."
如何抉择
从上述Taro 3架构来说,扭转了Taro1/2的重编译时的场面从而转向重运行时,其实重编译时的局限性不仅是对开发者的开发标准有更大的限度,也不利于保护taro框架的源码,因为一旦各厂商增删改了她们小程序的某个标准或者api时,要去保护降级taro的代码老本是比拟高的。
但这不意味着taro3肯定是最适宜的版本,同等条件下,编译时做的工作越多,也就意味着运行时做的工作越少,性能会更好。随时时代的进度,硬件的条件越来越好,就义硬件的前提下可能带来更好的开发体验兴许是比拟理智的抉择,然而在逻辑比较复杂或者须要更多运行内存的小程序,还是要侧重于重编译时的Taro2!
迁徙指南
降级Taro Next前,请仔细阅读官网迁徙指南
转换内部款式 withExternalStyle
Taro1/2 中需指定addGlobalClass
能力应用内部的 className,然而 Taro3 晋升了所有的款式文件到 common.css 中,所以须要对外部款式进行转换。
转换 hooks withHooks
Taro1/2 中所有的 hooks 和一些非凡的性能组件如 Component, memo 等从 Taro 中导出。但 Taro3 中只保护了 Taro 独有的 hooks 和性能组件,所以将这些从 Taro2 中拆分进去。
转换类组件生命周期
React 中有一些废除的生命周期须要加上 UNSAFE 的前缀标识。
降级 mobx4 到 mobx6
如我的项目应用了mobx,请留神此条规定。
装璜器目前计划不稳固,在 mobx6 中更是缩小了装璜器的应用。而且 Taro3 中应用 mobx-react 而不是由 Taro 保护的 mobx-taro。
转换页面配置
页面配置文件独自拆分进去。
转换路由援用
拜访路由和路由参数应用 Taro3 的新的 api。
转换作用域援用 withScope
Taro1/2 应用编译时的框架,Taro3 应用的是运行时的框架,所以 scope 间接废除了。在转换中尝试进行兼容解决。
转换 hidden 属性
Taro1/2 中废除了自定义的一个属性 hidden。
将全局款式的 css 批改为 module.less
Taro3 中为了缩小组件款式文件的痛点,将所有的独自作用域的款式文件全副都晋升到了全局。间接转换后如不应用 css module,则会产生大量的款式凌乱干预。所以为了放弃款式的一致性,须要把款式进行转换,将 css 转换为 css module。
package.json
所依赖的 taro 极其相干的依赖手动更改(截止 2022-01-25,Taro 最新版 3.4.0)
{ "@tarojs/cli": "3.3.17", "@tarojs/components": "3.3.17", "@tarojs/react": "3.3.17", "@tarojs/runtime": "3.3.17", "@tarojs/taro": "3.3.17",}
删除掉 taro1/2 中的 config/index.js 中的对于 babel 的配置,新增文件babel.config.js
module.exports = { presets: [ [ 'taro', { framework: 'react', ts: true, }, ], ],};
配置 config/index.js 中,指定应用的框架为 react
{ framework: 'react',}
批改我的项目入口文件 app.ts
// 批改render函数,默认render this.props.childrenrender() { return this.props.children}// 批改导出,间接将App导出export default App;// Taro.render(<App />, document.getElementById('app'));
原生组件的应用
“Taro3 的组件是没有配置文件的,因而 usingComponents 必须配置在“页面”的配置文件中”。然而 Taro1/2 的组件容许申明配置文件,所以在 Taro3 中须要把这些原生组件的配置申明晋升到具体援用具体的页面。可参考 #withUsingComponentForHaicaoyun
组件标签废除
在 Taro1/2 中,对应的组件将会编译成同名的组件。例如 HcyButton 组件编译成 hcy-button,所以如果我的项目中解决款式文件时对对应的款式做了定义,那么在 Taro3 中须要手动进行批改。
page.$component
的应用
在 Taro1/2 中容许通过$component 的形式拜访具体组件的 Taro 实例,进而能够拜访类组件的任意办法和属性,甚至批改其状态。例如上面示例,拜访上个页面的实例,并设置其状态
const pages = getCurrentPages();const prevPage = pages[pages.length - 2];const prevPageInstance = prevPage.$component;prevPageInstance.setState({ formItems: [],});
这种在 Taro3 中并没有简略的替换计划,只能对所有应用这部分的中央进行一种适合的重构
taro2升taro3中可能遇到的报错
- Error: module "app.js" is not defined;module "common.js" is not defined (分包后公共组件打包问题)
- webpack Parser.pp$4.raise 报错 (webpack环境编辑应用的DOMAIN='',应该应用DOMAIN='""')
- Can't resolve './style/index.scss' (taro ui2.+和taro3.+版本不兼容)
- TypeError: Cannot read property 'prototype' of undefined (留神第三方库的依赖援用导致不兼容问题)
- MobX,Store Is Not Available, Make Sure It Is Provided By Some Provider (入口文件app.js应用<Provider {...store}></Provider>)注入全局store
- TypeError: Cannot read property 'getBehaviorPageData' of undefined (https://github.com/NervJS/tar...)(Taro.getCurrentPages获取到的page实例上没有$component)
- taro门路别名须要在webpack也配置一下
- 款式错乱问题,taro3中如不应用css module,则默认全局款式。
开发Taro2注意事项
凭记忆写下几点,具体问题可能与版本号也有关系,仅供参考
- 有状态组件尽量应用类组件开发,在页面中尤其留神这点,函数式组件中hooks和一些api性能bug较多,甚至某些钩子呈现不执行的bug
- 函数式组件中无奈通过
Taro.createSelectorQuery
获取元素信息,因为taro2须要传递scope,而在函数组件中无奈获取,及时应用useScope
useEffect
和useEffectLayout
执行机会与一般的react我的项目有区别useDidShow
在抖音端不执行Taro.hideLoading
微信真机上会同时敞开Taro.showToast
- 组件中不能导出常量,如果须要常量,须要另开一个文件独自导出应用
- jsx中渲染函数前缀必须是render结尾,如
renderItem = () => xxx
- Jsx中应用switch语法不能用default分支,会提醒你逻辑多余
- jsx中试用if..else..语法渲染节点,有时候并不会如你所意,尝试定义一个变量node,在分支中赋值给node后,最终return这个node节点解决问题
- 如果应用了mobx,抖音端在jsx条件渲染的时候须要用
toJS
包一下,如:toJS(list).length > 0 && <View>xxx</View>
Swiper
组件的nextMargin
和previousMargin
属性在h5端有效- h5有时候容器高度会比小程序出现的高,需设置
box-sizing: border-box;
- 不应用
View
、Text
标签选择器,H5内不失效。解决方案:应用className
开发Taro3注意事项
凭记忆写下几点,具体问题可能与版本号也有关系,仅供参考
更新组件会把兄弟节点也从新渲染了,问题形容
解决方案:给兄弟节点或本身减少层级
- 应用
Taro.createAnimation
,animationData
的初始值不能为null
,否则适度动画的成果会生效,间接出现最终的款式,解决这一问题能够应用{}
- 版本3.4.0之前
Taro.createAnimation
在H5端生效 - 因为层级过深导致的渲染问题能够尝试应用
CustomWrapper
组件包裹,它的作用是创立一个原生自定义组件。对后辈节点的setData
将由此自定义组件进行调用,达到部分更新的成果,从而晋升更新性能。 - video组件有时在第一次渲染的时候获取不到时长,无奈自动播放问题。
- 伪元素和伪类在小程序端生效
- 全局款式问题,taro3中如果不是css module,则默认款式文件作用所有组件
Image
在h5的实现是有一层包装层,这点在taro2中同样存在ScrollView
中应用position: sticky
有效,这点在taro2中同样存在- hidden异样,通过
state
数据管制显隐,不会失效。解决方案:通过三目运算解决