当前位置:   article > 正文

LazyForEach常见使用问题

lazyforeach

       

目录

1、渲染结果非预期

2、重新渲染时图片闪烁

3、@ObjectLink属性变化UI未更新


        上篇文章中我们介绍了LazyForEach的基本使用,展示了如何使用LazyForEach构造一个列表,并演示数据的添加、删除、修改如何与LazyForEach配合并正确的更新UI。本篇将介绍使用LazyForEach的时候会遇到的一些常见问题

1、渲染结果非预期

        代码如下:

  1. import { SimpleStringDataSource } from './base/LazyForeach';
  2. @Entry
  3. @Component
  4. struct LazyForEachDemo3Page {
  5. private data: SimpleStringDataSource = new SimpleStringDataSource();
  6. aboutToAppear() {
  7. for (let i = 0; i <= 20; i++) {
  8. this.data.pushData(`Hello ${i}`)
  9. }
  10. }
  11. build() {
  12. List({ space: 3 }) {
  13. LazyForEach(this.data, (item: string, index: number) => {
  14. ListItem() {
  15. Row() {
  16. Text(item).fontSize(50)
  17. .onAppear(() => {
  18. console.info("appear:" + item)
  19. })
  20. }.margin({ left: 10, right: 10 })
  21. }
  22. .onClick(() => {
  23. // 点击删除子组件
  24. this.data.deleteData(index);
  25. // 重置所有子组件的index索引
  26. // this.data.reloadData();
  27. })
  28. }, (item: string, index: number) => item + index.toString())
  29. }.cachedCount(5).width('100%').height('100%')
  30. }
  31. }

        运行结果如下:

        

        当我们多次点击子组件时,会发现删除的并不一定是我们点击的那个子组件。原因是当我们删除了某一个子组件后,位于该子组件对应的数据项之后的各数据项,其index均应减1,但实际上后续的数据项对应的子组件仍然使用的是最初分配的index,其itemGenerator中的index并没有发生变化,所以删除结果和预期不符。如何修复呢?把注释的那行代码打开即可(在删除一个数据项后调用reloadData方法,重建后面的数据项,以达到更新index索引的目的)。

2、重新渲染时图片闪烁

        如下代码只更新文本时,会引起图片的更新,看上去发生了闪烁:

  1. import { StringData } from './base/LazyData';
  2. import { ComplexDataSource } from './base/LazyForeach';
  3. @Entry
  4. @Component
  5. struct LazyRenderDemo4Page {
  6. private moved: number[] = [];
  7. private data: ComplexDataSource = new ComplexDataSource();
  8. aboutToAppear() {
  9. for (let i = 0; i <= 20; i++) {
  10. this.data.pushData(new StringData(`Hello ${i}`, $r('app.media.girl1')));
  11. }
  12. }
  13. build() {
  14. List({ space: 3 }) {
  15. LazyForEach(this.data, (item: StringData, index: number) => {
  16. ListItem() {
  17. Column() {
  18. Text(item.message).fontSize(50)
  19. .onAppear(() => {
  20. console.info("appear:" + item.message)
  21. })
  22. Image(item.imgSrc)
  23. .width(500)
  24. .height(200)
  25. }.margin({ left: 10, right: 10 })
  26. }
  27. .onClick(() => {
  28. item.message += '00';
  29. this.data.reloadData();
  30. })
  31. }, (item: StringData, index: number) => JSON.stringify(item))
  32. }.cachedCount(5).width('100%').height('100%')
  33. }
  34. }

         运行效果如下:

更新文本时,图片闪烁

        在我们点击ListItem子组件时,我们只改变了数据项的message属性,但是LazyForEach的刷新机制会导致整个ListItem被重建。由于Image组件是异步刷新,所以视觉上图片会发生闪烁。为了解决这种情况我们应该使用@ObjectLink和@Observed去单独刷新使用了item.message的Text组件(代码里还修改了键值对的生成规则)。

  1. import { StringData } from './base/LazyData';
  2. import { ComplexDataSource } from './base/LazyForeach';
  3. @Entry
  4. @Component
  5. struct LazyRenderDemo4Page {
  6. private moved: number[] = [];
  7. private data: ComplexDataSource = new ComplexDataSource();
  8. aboutToAppear() {
  9. for (let i = 0; i <= 20; i++) {
  10. this.data.pushData(new StringData(`Hello ${i}`, $r('app.media.girl1')));
  11. }
  12. }
  13. build() {
  14. List({ space: 3 }) {
  15. LazyForEach(this.data, (item: StringData, index: number) => {
  16. ListItem() {
  17. LazyDemo4ChildComponent({data: item})
  18. }
  19. .onClick(() => {
  20. item.message += '00';
  21. this.data.reloadData();
  22. })
  23. }, (item: StringData, index: number) => {
  24. //key不变,此时只更新相关item的数据
  25. return index.toString()
  26. })
  27. }.cachedCount(5).width('100%').height('100%')
  28. }
  29. }
  30. @Component
  31. struct LazyDemo4ChildComponent {
  32. @ObjectLink data: StringData
  33. build() {
  34. Column() {
  35. Text(this.data.message).fontSize(50)
  36. .onAppear(() => {
  37. console.info("appear:" + this.data.message)
  38. })
  39. Image(this.data.imgSrc)
  40. .width(500)
  41. .height(200)
  42. }.margin({ left: 10, right: 10 })
  43. }
  44. }

        修复后运行效果如下:

只更新文本,图片不闪烁

3、@ObjectLink属性变化UI未更新

  1. import { NestedString, StringDataV2 } from './base/LazyData';
  2. import { MyDataSource } from './base/LazyForeach';
  3. @Entry
  4. @Component
  5. struct LazyRenderDemo5Page {
  6. @State data: MyDataSource<StringDataV2> = new MyDataSource<StringDataV2>();
  7. aboutToAppear() {
  8. for (let i = 0; i <= 20; i++) {
  9. this.data.pushData(new StringDataV2(new NestedString(`Hello ${i}`)));
  10. }
  11. }
  12. build() {
  13. List({ space: 3 }) {
  14. LazyForEach(this.data, (item: StringDataV2, index: number) => {
  15. ListItem() {
  16. LazyRenderDemo5ChildComponent({data: item})
  17. }
  18. .onClick(() => {
  19. // item.message.message += '0';
  20. item.message = new NestedString(item.message.message + '0');
  21. })
  22. }, (item: StringDataV2, index: number) => item.toString() + index.toString())
  23. }.cachedCount(5).width('100%').width('100%')
  24. }
  25. }
  26. @Component
  27. struct LazyRenderDemo5ChildComponent {
  28. @ObjectLink data: StringDataV2
  29. build() {
  30. Row() {
  31. Text(this.data.message.message).fontSize(50)
  32. .onAppear(() => {
  33. console.info("appear:" + this.data.message.message)
  34. })
  35. }.margin({ left: 10, right: 10 })
  36. }
  37. }
  38. @Observed
  39. export class StringDataV2 {
  40. message: NestedString;
  41. constructor(message: NestedString) {
  42. this.message = message;
  43. }
  44. }
  45. @Observed
  46. export class NestedString {
  47. message: string;
  48. constructor(message: string) {
  49. this.message = message;
  50. }
  51. }

        @ObjectLink装饰的成员变量仅能监听到其子属性的变化,再深入嵌套的属性便无法观测到了,因此我们只能改变它的子属性去通知对应组件重新渲染,具体请查看@ObjectLink与@Observed的详细使用方法和限制条件。

        如何修复呢?既然不支持2层嵌套属性变化,那就在第一场嵌套属性变化上作文章,修复代码如下:

  1. onClick(() => {
  2. item.message = new NestedString(item.message.message + '0');
  3. })

        比较简单,就是修改第一层嵌套属性的值(@ObjectLink能监听到该层的变化)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/249714
推荐阅读
相关标签
  

闽ICP备14008679号