HarmonyOS 鸿蒙Next中Toggle组件初始化赋值会走onChange回调?
HarmonyOS 鸿蒙Next中Toggle组件初始化赋值会走onChange回调? Toggle初始化复制会走一次onChange回调,一般使用场景都是onChange回调中请求接口,这样就会无缘无故的发送一次请求。这不得开发多写代码处理逻辑吗
当通过@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中包含接口请求等操作,可能会导致不必要的调用。建议在初始化时通过条件判断或状态标记来避免这一问题,例如设置一个初始化完成的标志位,仅在非初始化阶段处理回调行为。