HarmonyOS 鸿蒙Next中Toggle组件初始化赋值会走onChange回调?

HarmonyOS 鸿蒙Next中Toggle组件初始化赋值会走onChange回调? Toggle初始化复制会走一次onChange回调,一般使用场景都是onChange回调中请求接口,这样就会无缘无故的发送一次请求。这不得开发多写代码处理逻辑吗

8 回复

当通过@State@Link修饰的变量直接初始化Toggle的isOn属性时,不会触发onChange回调。例如:

[@State](/user/State) isChecked: boolean = true;

Toggle({ type: ToggleType.Switch, isOn: $$this.isChecked })

  .onChange((isOn: boolean) => {

    console.log('状态变化:', isOn);  // 初始化时不会打印

  })

若在组件生命周期中通过异步操作或方法动态设置初始值,可能因数据更新触发onChange回调。例如:

aboutToAppear() {

  fetchStatus().then(status => {

    this.isChecked = status;  // 此处赋值可能触发回调

  });

}

解决方案:

方案1/通过引入标志位跳过首次回调

[@State](/user/State) isChecked: boolean = true;

private isInitialized: boolean = false;

Toggle({ type: ToggleType.Switch, isOn: $$this.isChecked })

  .onChange((isOn: boolean) => {

    if (!this.isInitialized) {

      this.isInitialized = true;

      return;

    }

    // 实际业务逻辑(如发送请求)

    this.sendRequest(isOn);

  })

方案2/通过setTimeout延迟初始化赋值

aboutToAppear() {

  setTimeout(() => {

    this.isChecked = initialValue;  // 延迟至组件渲染完成后赋值

  }, 0);

}

方案3/通过独立变量管理业务状态

[@State](/user/State) uiChecked: boolean = true;  // 仅用于UI显示

private actualChecked: boolean = true;  // 实际业务状态

Toggle({ type: ToggleType.Switch, isOn: $$this.uiChecked })

  .onChange((isOn: boolean) => {

    this.actualChecked = isOn;

    this.sendRequest(isOn);

  })

更多关于HarmonyOS 鸿蒙Next中Toggle组件初始化赋值会走onChange回调?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在组件初始化阶段,通过标志位或条件判断避免首次渲染触发回调。

楼主这样的场景可以尝试自己封装一个自定义组件来实现

Toggle只提供了切换后的回调,楼主也可以用另外的机制将值重新改回去,onChange只负责回调结果

onChange(callback: (isOn: boolean) => void)

参考文档:Toggle-按钮与选择-ArkTS组件-ArkUI(方舟UI框架)-应用框架 - 华为HarmonyOS开发者

期待HarmonyOS能在未来带来更多创新的技术和理念。

又发现了一个不合理的地方,比如我要点击开关拉黑用户,一般都会弹一个提示框让用户确定,这玩意都无法拦截,一点击就切换了

// PromptActionClass.ets
import { BusinessError } from '@kit.BasicServicesKit';
import { ComponentContent, promptAction, UIContext } from '@kit.ArkUI';

export class PromptActionClass {
  static ctx: UIContext;
  static contentNode: ComponentContent<Object>;
  static options: promptAction.BaseDialogOptions;

  static setContext(context: UIContext) {
    PromptActionClass.ctx = context;
  }

  static setContentNode(node: ComponentContent<Object>) {
    PromptActionClass.contentNode = node;
  }

  static setOptions(options: promptAction.BaseDialogOptions) {
    PromptActionClass.options = options;
  }

  static openDialog() {
    if (PromptActionClass.contentNode !== null) {
      PromptActionClass.ctx.getPromptAction().openCustomDialog(PromptActionClass.contentNode, PromptActionClass.options)
        .then(() => {
          console.info('OpenCustomDialog complete.');
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }

  static closeDialog() {
    if (PromptActionClass.contentNode !== null) {
      PromptActionClass.ctx.getPromptAction().closeCustomDialog(PromptActionClass.contentNode)
        .then(() => {
          console.info('CloseCustomDialog complete.');
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }

  static updateDialog(options: promptAction.BaseDialogOptions) {
    if (PromptActionClass.contentNode !== null) {
      PromptActionClass.ctx.getPromptAction().updateCustomDialog(PromptActionClass.contentNode, options)
        .then(() => {
          console.info('UpdateCustomDialog complete.');
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }
}
// Index.ets
import { ComponentContent } from '@kit.ArkUI';
import { PromptActionClass } from './PromptActionClass';

class Params {
  text:string = ''
  click: () => void;
  cancel: () => void;

  constructor(text:string,click: () => void, cancel: () => void = ()=>{}) {
    this.text = text;
    this.click = click;
    this.cancel = cancel;
  }
}

@Builder
function buildText(params: Params) {
  Column() {
    Text(params.text)
      .fontSize(50)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 36 })
    Button('取消')
      .onClick(() => {
        params.cancel();
        PromptActionClass.closeDialog();
      })
    Button('确定')
      .onClick(() => {
        params.click();
        PromptActionClass.closeDialog();
      })
  }.backgroundColor('#FFF0F0F0')
}

@Entry
@Component
struct Index {
  @State isOn: number = 0;//0:未打开 1:打开中 2:已打开
  private ctx: UIContext = this.getUIContext();
  private contentNode: ComponentContent<Object> =
    new ComponentContent(this.ctx, wrapBuilder(buildText), new Params("确认打开吗",()=>{
      this.isOn = 2
    }))

  aboutToAppear(): void {
    PromptActionClass.setContext(this.ctx);
    PromptActionClass.setContentNode(this.contentNode);
    PromptActionClass.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } });
  }

  build() {
    Row() {
      Column() {
        Toggle({
          type:ToggleType.Switch,
          isOn:this.isOn === 2 ? true : false,
        })
          .onChange((value: boolean) => {
            if(value){
              if(this.isOn === 0){
                this.isOn = 1
                PromptActionClass.openDialog()
              }
            }else{
              this.isOn = 0
            }
          })
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }
}

在HarmonyOS Next中,Toggle组件初始化赋值时不会触发onChange回调。onChange回调仅在用户交互(如点击)导致状态改变时执行。初始化设置的状态变化属于程序行为,不视为用户触发的变更,因此不会调用onChange。

是的,在HarmonyOS Next中,Toggle组件的初始化赋值确实会触发onChange回调。这是因为组件在初始状态设置时会检测值变化,从而执行回调逻辑。

如果onChange中包含接口请求等操作,可能会导致不必要的调用。建议在初始化时通过条件判断或状态标记来避免这一问题,例如设置一个初始化完成的标志位,仅在非初始化阶段处理回调行为。

回到顶部