
背景
UU跑腿小程序作为公司的主要流量入口,对公司的业务发展起到了很大的推动作用。目前我们已在微信、支付宝、百度、抖音、高德平台上架小程序。而随着公司业务的发展,目前的Taro2版本内置的平台已无法支持我们的业务需求。而自Taro3.0后支持了开发式插件系统,可以让开发者根据自己的业务需求去扩展平台,且更好的跨框架特性等,都值得我们去拥抱Taro3.0。本文主要介绍taro升级过程中出现的问题及解决方案。
原始版本:Taro2.2.26
升级版本:Taro3.3.12 + React17.0.0 + Redux4.0.0
参考文档: 【官方迁移指南】
目录
- 背景
- 升级问题
- 更新项目依赖
- 配置文件
- 启动项目
- 获取路由参数
- render函数
- redux
- 其他
- SourceMap 支持
- 平台兼容
升级问题
建议优先阅读官方迁移指南,指南中已对升级步骤做了详细的介绍,此文主要针对升级过程中存在的问题进行说明。
1. 更新项目依赖
官方文档中是直接更项目依赖的,但实际升级过程中,由于项目依赖包较多,且依赖版本无法是否应该升级,故建议新建项目,然后在新项目的基础上进行增量的添加自己项目包;
# 更新Cli
$ npm i -g @tarojs/cli@next
# 新建项目
$ taro init myApp
# 复制新项目的package.json文件覆盖当前项目的package.json(注意做好备份),
$ npm i xxx # 添加自己项目的依赖包
2. 配置文件
建议直接使用新项目的配置文件(config/**, 可直接复制文件夹),并在此基础上做针对项目的配置文件修改。

3. 启动项目
如果已参考官方指南完成了所有迁移工作,此时就可以尝试启动项目了,但启动的过程中可能会有很多的错误,那就需要根据控制台报错信息边改边启动了,一般的错误还是比较明显的。但有个样式报警(如下图),需要修改配置文件。
这个是因为多个文件引入了相同的样式文件,但是引入顺序不一样,可在配置文件中config/index.js配置忽略即可。
const config = {
mini: {
miniCssExtractPluginOption: {
ignoreOrder: true, // 忽略引入样式文件的顺序
},
}
}
4. 获取路由参数
Taro3.3版本在获取参数的时候存在Taro.getCurrentInstance().router
结果为null的情况(onShow中情况较多),目前Taro社区中暂无解决方案,此处建议做兼容处理。目前我们采取的处理办法如下,但如果有更好的办法,还望分享。
# 封装统一的获取路由参数的方案
const getTaroParams = (instance) => {
let params = {};
let ins = instance || Taro.getCurrentInstance();
try {
if(ins && ins.router) {
params = ins.router.params
} else { // 如果获取不到,从历史路由中获取
let pages = Taro.getCurrentPages();
let thisPage = pages[pages.length - 1];
if(thisPage && thisPage.options) {
params = thisPage.options;
}
}
} catch (err) { console.log(err)}
return params || {};
}
# -----------------页面调用 -------------------
class Page extends Component {
$instance = Taro.getCurrentInstance();
# 方法调用
componentDidShow() {
const params = getTaroParams(this.$instance);
}
}
5. render函数
在Taro2中的render方法中,taro框架为我们做了很多错误语法的兼容处理,但是升级Taro3中,所有的问题就一一暴露了出来。
5.1 组件引入
老版本中页面render函数中用的的组件是不需要引入的,页面也并不会报错,但是新版中所有的组件就必须一一引入,否则就会报错

需在顶部引入
import { Swipper } from '@tarojs/components'
5.2 为空判断
页面中用到的变量必须做非空判断,框架不再做兼容
<View>{ userInfo?.userName }</View>
5.3 &&逻辑
很多时候,我们会写如下代码
list.length && <View>...</View>
但在新版的项目中,如果list为空数组,此处展示在页面上则为’0’, 即需要确保&&
之前的变量或表达式必须是布尔类型。如遇此情况,可做以下修改
Boolean(list.length) && <View>...</View>
5.4 bind(this)
Taro2中,如果render中调用的方法没有bind(this), 也是可以直接调用的,但是Taro3就必须bind(this)
<View onClick={this.onSave.bind(this)}></View>
# OR
onSave = () => {
....
}
5.5获取页面元素
理论上我们再DidMount中获取元素是没有问题的, 但实际情况可能跟我们想想的不一样,经常会获取不到元素,如遇到此问题,建议做异步处理Taro.nextTick(() => {} )
class C extends Component {
componentDidMount() {
Taro.nextTick(()=> {
const query = Taro.createSelectorQuery().in(Taro.getCurrentInstance().page)
query.select('#pick-bar').boundingClientRect(res => {
...
}
}).exec()
}
}
redner() {
return <Viev id="pick-bar"></View>
}
}
5.6 hidden失效
# 此处失效
<View hidden={isShow}></View>
# 改为
{ isShow && <View></View> }
5.7 组件内部元素添加Id
有时候我们会在通过props传入组件内部Id(但并不建议在公共组件中通过外部传入id), 但如果存在相同的id, 或者id为空,会导致点击事件混乱,而且如果组件嵌套层级很深的话,很难发现此问题。
class C extends Component {
render() {
let id = this.props.id; # 如果id为空或者id相同,会造成页面点击混乱
return <View id={id}></View>
}
}
6. redux
在Taro2中, connect
函数中的mapDispatchToProps
会默认传入dispatch
, 但Taro3中,不再做支持, 需要自己添加返回, 如下所示:
class C extends Component {
...
onSave() {
let { dispatch } = this.props;
dispatch({ type: 'app/save'})
}
...
}
const mapDispatchToProps = dispatch => {
return {
dispatch, # 需自己添加
update: (state) => dispatch.app.updateSate(state)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(C)
其他
1. SourceMap支持
Taro2中并不支持SourceMap, 导致在平台的错误日志中根本无法定位错误位置,但在Taro3中新增了对SourceMap的支持,如需使用,可在config/index.js中做如下配置
const config = {
mini: {
enableSourceMap: true,
sourceMapType: 'source-map',
}
}
支持后的错误信息如下图所示

2. 平台兼容
2.1 百度
对于Taro3的多平台支持,微信、支付宝、抖音的支持度与Taro2差别不大,但Taro3的百度小程序flex布局存在诸多问题,尽管Taro官方说已做优化,但问题依然存在,在论坛上看有人提出的一个解决办法, 尝试后发现能解决大部分flex布局的问题。
# 在src/app.scss(.css)中加入此全局样式
swan-template {
display: contents;
}
但除此之外,百度依然有很多样式兼容问题,并未一一解决,建议对不兼容的样式,可尝试做降级处理。