为什么要获取组件实例
在Taro中,部分与wxml相关的api,如:Taro.createSelectorQuery、Taro.createIntersectionObserver,在自定义组件(小程序组件)中使用时,需要使用this.createSelectorQuery来代替。但是在Function组件中,是无法直接获取到当前自定义组件的this实例的。
大部分情况下,在我们的React组件中直接使用Taro.createSelectorQuery这种api是没有问题的,因为taro在编译时,并没有把我们的组件直接作为小程序原生组件来渲染,还是直接在主页面中进行渲染的。
如下:
<!--页面wxml-->
<View className='select-car-page'>
<NavBar back home title='请选择车型' />
<View className='select-car-warp'>
<SearchInput bindTire={bindTire} />
<BrandList />
</View>
</View>
在我们的页面中,使用了3个函数组件NavBar、SearchInput、BrandList,但是在Taro中的实际渲染,并没有将这3个组件作为小程序原生组件来渲染。真实的渲染结果如下:
所以,我们在这些组件内部使用这些api时,还是可以直接使用Taro.Api进行使用。
但是有2种情况下,是比较特殊的,需要获取到当前小程序组件的实例。
dom层级超过指定层级时,在Taro官网中,也有说明,如下:
对于不支持模板递归的小程序(微信、QQ、京东小程序),在
DOM层级达到一定数量后,Taro会使用原生自定义组件协助递归。 简单理解就是DOM结构超过N层后,会使用原生自定义组件进行渲染。N默认是16层,可以通过修改配置项baseLevel修改N。
- 手动使用了
CustomWrapper组件。
为了解决全局配置不灵活的问题,我们增加了一个基础组件
CustomWrapper。它的作用是创建一个原生自定义组件,对后代节点的setData将由此自定义组件进行调用,达到局部更新的效果。
其实上面2中场景,都是使用了小程序原生自定义组件,导致出现不同作用域,无法直接通过Taro.createSelectorQuery获取组件内的dom节点。第1种是被动使用,通常不容易被注意到;第2种是主动使用,通常用来性能优化。所以我们在这种组件内部,需要通过组件实例来调用相应的api。
使用
CustomWrapper组件 包裹遇到更新性能问题的模块,可以提升更新时的性能
可以再看下,当我们使用 CustomWrapper 包裹我们组件内容时,渲染的结果如下:
可以看到,实际会使用小程序的自定义组件CustomWrapper来进行渲染。
那当我们遇到这种必须使用自定义组件的时候,在函数组件中,应该如何获取当前组件的实例呢?
获取小程序组件实例方法
可以先获取到页面实例,在通过页面实例的selectComponent方法获取组件实例,如下:
<!--BrandList组件内容-->
<CustomWrapper id='brandList'>
<!--组件内部内容-->
<>...</>
</CustomWrapper>
// 获取当前自定义组件实例
const page = Taro.getCurrentInstance().page;
const that = page.selectComponent('#brandList');
// 通过组件实例调用相应的api
that.createSelectorQuery()
这种方式如果在嵌套使用
CustomWrapper时,深层级的组件,就无法直接通过页面实例来获取了,需要通过父组件实例获取。
网上看到有些历史方案,在函数组件中使用 Taro 的 useScope hook ,在class组件中使用 this.$scope,来获取当前作用域,但是目前的Taro3.x版本中已经没有这个hook和属性了。希望后续能够有更好的解决方案。