HarmonyOS 鸿蒙Next 组件间的状态管理困难

HarmonyOS 鸿蒙Next 组件间的状态管理困难

目标及问题

问题:
下拉菜单中只有一个文件。更新的列表数据没能同步到这个选择组件中。

主界面的相关代码:

变量声明部分:

@Entry
@Component
struct ScanPageIndex {
  private breakpointSystem: BreakpointSystem = new BreakpointSystem()
  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'
  [@State](/user/State) dir: string = 'Ld';
  [@State](/user/State) cfglist: string[] = [];
  [@State](/user/State) linlist: string[] = [];
  [@State](/user/State) pagetitle: string = '连接设备';
  [@State](/user/State) SSIDnotEmpty: boolean = false;
  [@State](/user/State) PWDnotEmpty: boolean = false;
  [@State](/user/State) ssid: string = "";
  [@State](/user/State) fileisSelect: boolean  = false;

组件调用部分:

                Button("创建配置")
                  .fontSize(20)
                  .height(40)
                  .width(150)
                  .fontWeight(FontWeight.Bold)
                  .onClick(async () => {
                    FileUtils.newFile('/' + this.cfgFileName);
                    this.filelist = await FileUtils.listFiles(getContext(this).filesDir,'.cfg','.csv');
                    ToastUtils(this.filelist.length.toString());
                    this.cfglist = await FileUtils.listFiles(getContext(this).filesDir,'.cfg');
                    this.cfglen = this.cfglist.length;
                    this.linlist = await FileUtils.listFiles(getContext(this).filesDir,'.csv');
                    this.linlen = this.linlist.length;
                  })
              }

              if(this.cfglist.length) SelectExt({SelectIndex:0,seletTitle:'选择配置文件',thisSetID:0,RecordTitle:'cfgFile',tobeRecord:false,seletItems: this.cfglist })
              if(this.linlist.length) SelectExt({SelectIndex:0,seletTitle:'选择线性配置',thisSetID:1,RecordTitle:'linarFile',tobeRecord:false,seletItems:this.linlist})
              //  [@State](/user/State) SelectIndex:number=0;

组件的实现代码

const TAG = 'SelectExt'
@Component
export struct SelectExt {
  [@State](/user/State) SelectIndex:number=0;
  [@State](/user/State) thisSetID:number=0;
  [@State](/user/State) seletItems:Array<string>=[];
  [@State](/user/State) seletTitle:string='';
  [@State](/user/State) RecordTitle:string='';
  [@State](/user/State) tobeRecord:boolean=false

  @Builder settingItem($$:{settingId: number, icon: Resource, title: string | Resource, showDivider: boolean}) {
    Stack() {
      if ($$.settingId == this.thisSetID) {
        Column() {
          Column()
           .backgroundColor(get_translucentSaturation_accent())
            .height('100%')
            .width('100%')
            .borderRadius(16)
        }
        .height('100%')
        .width('100%')
        .padding(3)
      }

      Column() {
        Row() {
          Image($$.icon)
            .height(24)
            .width(24)
          Text($$.title)
            .fontColor($r('app.color.text_level1'))
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .margin({ left: 16 })
        }
        .height(56)

        if ($$.showDivider) {
          Column() {
            Divider().width('100%').color($r('app.color.divider'))
          }.padding({ left: 40 })
        }
      }
      .padding({ left: 12, right: 12 })
      .alignItems(HorizontalAlign.Start)
      .width('100%')
    }
    .height(56)
    .width('100%')
  }

  @Builder settingSubTitle($$:{text: string}) {
    Row() {
      Text($$.text)
        .fontWeight(FontWeight.Medium)
        .fontColor($r('app.color.text_level2'))
        .fontSize(14)
      Image($r('app.media.ic_arrow_right'))
        .width(12)
        .height(24)
        .margin({ left: 4 })
    }
    .padding({ right: 12 })
    .justifyContent(FlexAlign.End)
  }

  @Builder selectMenu($$:{thisResource: Array<SelectionItem>, outPut: (value: number) => number}) {
    Column() {
      Column() {
        ForEach($$.thisResource, (item: SelectionItem, index: number) => {
          Column() {
            Column() {
              Text(item.title)
                .fontColor(item.index == $$.outPut(-1) ? get_accent() : $r('app.color.text_level1'))
                .fontSize(14)
            }
            .width('100%')
            .alignItems(HorizontalAlign.Start)
            .padding({ bottom: 12, top: 12 })
            .onTouch(() => {
              $$.outPut(item[1])
              console.info($$.outPut(-1).toString())
            })

            if (index != $$.thisResource.length - 1)
              Divider().color($r('app.color.divider'))
          }
          .width('100%')
        })
      }
      .padding({ left: 12, right: 12 })
    }
    .width(112)
    .justifyContent(FlexAlign.Start)
  }

  @Builder settingSelect($$:{thisResource: Array<SelectionItem>, outPut: (value: number) => number}) {
    Row() {
      Text($$.thisResource[$$.outPut(-1)][0])
        .fontColor($r('app.color.text_level1'))
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
      Image($r('app.media.ic_spinner_level1'))
        .width(24)
        .height(24)
    }
    .bindMenu(this.selectMenu({thisResource: $$.thisResource, outPut: $$.outPut}))
    .padding({ right: 12 })
    .justifyContent(FlexAlign.End)
  }

  build() {
    Column() {
      Stack({ alignContent: Alignment.End }) {
        this.settingItem({
          settingId: 9,
          icon: $r('app.media.ic_setting_calendarSet'),
          title: this.seletTitle,
          showDivider: true
        })
        this.settingSelect({ thisResource: builtSelectArray(this.seletItems), outPut: (value: number) => {
          if (value > -1) {
            this.SelectIndex = value
          if(this.tobeRecord)AppStorage.set(this.RecordTitle, value.toString());
          }
          return this.SelectIndex
        } })
      }.height(56).width('100%')
    }
    .width('100%')
  }
}

依据我的理解,主界面中的linlist 和 cfglist 都是@State,一旦创建文件后必然同步更新这两个列表数据。但是SelectExt的seletItems列表数据,只是在linList.len>0才更新一次。无法多次同步数据。又不能@provide@Customer,因为这两个组件的数据源不一致。请大师指教


更多关于HarmonyOS 鸿蒙Next 组件间的状态管理困难的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

更多关于HarmonyOS 鸿蒙Next 组件间的状态管理困难的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


不好意思,感觉@state @link 可以搞定。但是SelectExt的一个函数还是有问题。下面是测试程序

import { SelectExt } from '../common/utils/selectExt';
@Entry
@Component
struct Index {
  @State message: string = 'Hello World'
  @State text:string ='';
  @State filelist:string[]=[];
  @State cfglist:string[]=[];
  @State linlist:string[]= [];

  build() {
    Row() {
      Column() {
        List({ space: 5, initialIndex: 0 }) {
          ForEach(this.cfglist, (item) => {
            ListItem() {
              Text('' + item)
                .width('100%').height(40).fontSize(20)
                .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
            }
          }, item => item)
        }
        .listDirection(Axis.Vertical) // 排列方向
        .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
        .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
        .onScrollIndex((firstIndex: number, lastIndex: number) => {
          console.info('first' + firstIndex)
          console.info('last' + lastIndex)
        })
        .width('90%')
       
        TextInput({text:this.text,placeholder:'test intput hear'})
          .fontSize(40)
          .height(60)
          .width('80%')
          .backgroundColor('yellow')
          .onChange((value:string)=>{
              this.text=value;
          })
        Button('添加')
          .fontSize(40)
          .height(60)
          .onClick(()=>{
            this.filelist.push(this.text);
            if( this.text.indexOf('.cfg')>0)this.cfglist.push( this.text);
            if( this.text.indexOf('.csv')>0)this.linlist.push( this.text);
          })
         SelectExt({SelectIndex:0,seletTitle:'选择配置文件',thisSetID:0,RecordTitle:'cfgFile',tobeRecord:false,seletItems: $cfglist })
         SelectExt({SelectIndex:0,seletTitle:'选择线性配置',thisSetID:1,RecordTitle:'linarFile',tobeRecord:false,seletItems: $linlist})

      }
      .width('100%')
    }
    .height('100%')
  }
}

在HarmonyOS鸿蒙Next中,组件间的状态管理主要通过以下几种机制实现:

  1. @State@Prop@State用于定义组件内部的状态,当状态变化时,组件会自动重新渲染。@Prop用于父组件向子组件传递状态,子组件可以读取但不能直接修改父组件的状态。

  2. @Link@Link用于双向绑定,父组件和子组件可以共享同一个状态,任何一方的修改都会反映到另一方。

  3. @Observed@ObjectLink:用于管理复杂对象的状态。@Observed标记的类会被系统观察,当对象属性变化时,@ObjectLink绑定的组件会自动更新。

  4. @Watch:用于监听状态变化,当指定状态发生变化时,会触发回调函数。

  5. 全局状态管理:通过AppStorage或LocalStorage实现全局状态管理,AppStorage用于应用全局状态,LocalStorage用于页面级别的状态管理。

这些机制提供了灵活的状态管理方式,开发者可以根据具体需求选择合适的方案。

回到顶部