HarmonyOS 鸿蒙Next `LazyForEach`和`Reusable`在数据源index:0处依次新增多个元素的问题

发布于 1周前 作者 h691938207 来自 鸿蒙OS

HarmonyOS 鸿蒙Next LazyForEachReusable在数据源index:0处依次新增多个元素的问题
大佬们,我根据组件复用官方示例里的代码,改了一下,因为我需要在数据源的index:0处新增元素,并会在复用的子组件内触发一个回调方法执行父组件中的方法,见如下关键代码:

父组件:

// 数据源index:0处新增元素、通知数据源listener新增、通知数据源listener重载
Button('列表index:0处新增').onClick(() => {
    let uuid = util.generateRandomUUID().substring(0,7)
    // 忽略ColorModel里的构造参数,这里表示unshift了一个对象并reload数据源,unshift里已经通知数据源listener新增了。
    this.colorData.unshift(new ColorModel(uuid, uuid, Color.Black))
    this.colorData.dataReload()
})

// this.colorData已经实现了IDataSource接口
LazyForEach(this.colorData, (colorModel: ColorModel, index: number) => {
    ListItem() {
        OneMomentNoModifier({
          colorModel,
          index,
          action: () => {
            // 在点击Button新增超过1个元素之后,父组件打印的就是错的了,怀疑是复用组件的问题
            hilog.info(0x0000, TAG, `#parent#action(): id[${colorModel.id}], index[${index}]`);
          }
        })
    }
}, (color: ColorModel, index: number) => `${color.id}_${index}`)

子组件:

@Reusable
@Component
export struct OneMomentNoModifier {
    @Prop colorModel: ColorModel
    @Prop index: number
    action?: () => void

    build() {
        Column() {
            // 子组件显示的始终是对的
            Text(this.colorModel.id + '/' +this.index)
        }
        .onclick(() => {
            if (undefined !== this.action) {
                hilog.info(0x0000, TAG, `#child#action(): id[${this.colorModel.id}], index[${this.index}]`);
                this.action()
            }
        })
    }

发现同时使用LazyForEachReusable之后,通知数据源在index:0处新增数据,this.notifyDataAdd(0)并reload数据源,超过1条之后,父组件在执行子组件回调的时候使用colorModel对象里的数据就是不对的了。

我现在的解决办法是在子组件的action回调内,将colorModel以参数形式传出来,因为子组件通过@Prop得到的对象始终是对的:

子组件

// 子组件
this.action(this.colorModel)

// 父组件
action: (obj: ColorModel) => { 
    // 使用obj
}

这样虽然问题解决了,但是父组件中使用colorModel时,用的colorModel是从父里的LazyForEach赋值 -> 子通过回调传参 -> 父接收回调参数 得来的,总觉得不对劲,想请问大家发生这样的问题是因为什么?我现在怀疑是复用组件的问题,但又不知道怎么解决…(在index:0处新增一个,意味着复用了刚刚列表底部被顶下去消失不见被回收的组件,被回收的组件内的action还是第一次渲染时候的箭头函数?并没有被重新赋值吗?但是子组件内的action又不能加@Prop注解,会报错…)

这里是输出的日志:

日志图片

新增第一个时是对的,应该是ListcachedCount设置的5,屏幕显示条数 + 5正好 >= 总条目10。所以应该是每次新增数据的时候,父组件回调里的colorModel就是错的。


更多关于HarmonyOS 鸿蒙Next `LazyForEach`和`Reusable`在数据源index:0处依次新增多个元素的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

每次新增ColorModel时,LazyForEach里所有子节点的索引都变动了,所有子节点都需要重新渲染,因为子组件标记了@Reusable,所以旧的节点没有被销毁,放入复用缓存中,会在下一次新增时被复用。复用时父组件action不会重新渲染,所以父组件都是旧的参数。

[@Reusable](/user/Reusable)
@Component
export struct OneMomentNoModifier {
  @Prop colorModel: ColorModel
  @Prop index: number
  action?: () => void
  uid: string = ''
  index2: number = 0
  build() {
    Column() {
      Text(this.uid + '/' + this.index2)
    }
    .width('80%')
    .height('8%')
    .onClick(() => {
    })
    .backgroundColor(this.colorModel.color)
    .margin({ top: 10 })
  }
}

在子组件打断点,新增渲染时可以看出,每次新增都都会渲染2次子组件。渲染效果

次数 当前显示 缓存池
1 +a0
2 a1,+b0 a0
3 a2,b1+a0 a1,b0
4 a3,b2+a1,b0 a2,b1,a0
5 a4,b3+a2,b1,a0 a3,b2,a1,b0
6 a5,b4+a3,b2,a1,b0 a4,b3,a2,b1,a0

从缓存池中获取已缓存的子组件,子组件不够时新渲染组件,同时把当前的所有节点放入缓存池中。因为总是重复从缓存池中获取组件,所以参数始终是a和b

更多关于HarmonyOS 鸿蒙Next `LazyForEach`和`Reusable`在数据源index:0处依次新增多个元素的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


也就是说我现在除了现有的解决办法,只有不用复用组件才可以实现这个父组件action里正确的效果了嘛?

在HarmonyOS鸿蒙系统中,关于LazyForEachReusable在数据源index:0处依次新增多个元素的问题,这通常涉及到UI组件的复用和数据源的动态更新。

LazyForEach是鸿蒙系统中用于高效渲染列表数据的组件,而Reusable则是用于提高UI组件复用率的机制。当在数据源index:0处依次新增多个元素时,可能会遇到以下问题:

  1. UI更新延迟:由于数据源的更新和UI渲染之间存在一定的延迟,新增的元素可能不会立即显示在UI上。
  2. 组件复用错误:当数据源变化时,Reusable组件可能会因为复用机制而出现显示错误,特别是当在列表开头插入元素时。

为了解决这个问题,可以尝试以下方法:

  • 确保数据源更新后,及时通知UI组件进行重绘。
  • 检查LazyForEachReusable组件的使用方式,确保它们能够正确处理数据源的变化。
  • 如果问题依旧存在,可能需要考虑调整数据更新的策略,或者在数据更新后强制刷新UI组件。

如果问题依旧没法解决请联系官网客服,官网地址是 https://www.itying.com/category-93-b0.html

回到顶部