HarmonyOS鸿蒙Next中@State装饰器,置空数据后,打印显示为空,但是界面还是留有数据
HarmonyOS鸿蒙Next中@State装饰器,置空数据后,打印显示为空,但是界面还是留有数据 页面上有个清除按钮,全选数据后,点击清除。判断是否全选,如果全选,则置空数据并且将全选框置为非勾选状态。现在的问题是,清除后,日志显示数据为空,但是界面留有数据。关键点:如果删除this.isSelectedAll = false这行代码,则页面是正常的。这是什么原因?
api版本12,真机和模拟器都能复现。
import { promptAction } from '@kit.ArkUI'
interface ICodeAndName {
code: string
name: string
isSelected: boolean
}
@Entry
@Component
struct Index {
[@State](/user/State) listDataArr: ICodeAndName[] = []
[@State](/user/State) isSelectedAll: boolean = false
async clear() {
const index = this.listDataArr.findIndex(item => item.isSelected === true)
if (index === -1) {
promptAction.showToast({ message: '请勾选要清除的数据后再重试!' })
return
}
const i = await promptAction.showDialog({
title: 'showDialog Title Info',
message: 'Message Info',
buttons: [
{
text: '取消',
color: '#000000'
},
{
text: '确定',
color: '#000000'
}
]
})
if (i.index === 1) {
if (this.isSelectedAll) {
this.listDataArr = []
this.isSelectedAll = false
console.log(JSON.stringify(this.listDataArr))
}
}
}
aboutToAppear(): void {
this.listDataArr = [{
code: '1',
name: '1',
isSelected: false
}]
}
build() {
Column() {
Column() {
Text() {
Span('已经绑定')
Span(`${this.listDataArr.length}`)
.fontColor(Color.Red)
Span('条: ')
}
.width('100%')
.margin({ top: 15 })
.padding({ left: 50 })
.fontSize(20)
.fontWeight(600)
}
.width('100%')
.padding({ top: 15, bottom: 10 })
Column() {
Row() {
Column() {
CheckboxGroup({ group: 'checkboxGroup' })
.checkboxShape(CheckBoxShape.ROUNDED_SQUARE)
.height(16)
.aspectRatio(1)
.selectAll($$this.isSelectedAll)
}
.width(40)
Text('编码')
.layoutWeight(1)
.fontSize(24)
.textAlign(TextAlign.Center)
.border({ width: { left: 1, right: 1 } })
.padding({ top: 5, bottom: 5 })
Text('名称')
.layoutWeight(1)
.fontSize(24)
.textAlign(TextAlign.Center)
.padding({ top: 5, bottom: 5 })
}
.width('100%')
.border({ width: { bottom: 1 } })
.backgroundColor('#E4EAFF')
List() {
ForEach(this.listDataArr, (item: ICodeAndName, index: number) => {
ListItem() {
Row() {
Row() {
Checkbox({ group: 'checkboxGroup' })
.shape(CheckBoxShape.ROUNDED_SQUARE)
.height(16)
.aspectRatio(1)
.select(item.isSelected)
.onChange(() => {
this.listDataArr[index] = {
code: item.code,
name: item.name,
isSelected: !item.isSelected
} as ICodeAndName
})
}
.justifyContent(FlexAlign.Center)
.width(40)
Row() {
Text(item.code)
.layoutWeight(1)
.fontSize(19)
.textAlign(TextAlign.Center)
.border({ width: { left: 1, right: 1 } })
.padding({
top: 6,
bottom: 6,
left: 4,
right: 4
})
Text(item.name)
.layoutWeight(1)
.fontSize(19)
.textAlign(TextAlign.Center)
.padding({
top: 6,
bottom: 6,
left: 4,
right: 4
})
}
.layoutWeight(1)
}
.width('100%')
.border({ width: { bottom: 1 } })
}
})
}
.width('100%')
.layoutWeight(1)
}
.width('95%')
.layoutWeight(1)
.border({ width: 1 })
.margin({ top: 10, bottom: 10 })
Row() {
Text('清除')
.buttonExtend()
.onClick(() => {
this.clear()
})
Text('提交')
.buttonExtend()
.onClick(() => {
})
}
.width('100%')
.padding({ left: 40, right: 40 })
.justifyContent(FlexAlign.SpaceBetween)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F9')
.padding({ bottom: 20 })
}
}
@Extend(Text)
function buttonExtend() {
.width(100)
.height(35)
.textAlign(TextAlign.Center)
.backgroundColor('#126DDE')
.fontSize(20)
.fontColor('#fff')
.borderRadius(5)
}
更多关于HarmonyOS鸿蒙Next中@State装饰器,置空数据后,打印显示为空,但是界面还是留有数据的实战教程也可以访问 https://www.itying.com/category-93-b0.html
代码修改完毕,请查收!
import { promptAction } from '@kit.ArkUI'
interface ICodeAndName {
code: string
name: string
isSelected: boolean
}
@Entry
@Component
struct Index {
@State listDataArr: ICodeAndName[] = []
@State isSelectedAll: boolean = false
async clear() {
const index = this.listDataArr.findIndex(item => item.isSelected === true)
if (index === -1) {
promptAction.showToast({ message: '请勾选要清除的数据后再重试!' })
return
}
const i = await promptAction.showDialog({
title: 'showDialog Title Info',
message: 'Message Info',
buttons: [
{
text: '取消',
color: '#000000'
},
{
text: '确定',
color: '#000000'
}
]
})
if (i.index === 1) {
if (this.isSelectedAll) {
this.listDataArr.length = 0
this.isSelectedAll = false
console.log(JSON.stringify(this.listDataArr))
}
}
}
aboutToAppear(): void {
this.listDataArr = [{
code: '1',
name: '1',
isSelected: false
}]
}
build() {
Column() {
Column() {
Text() {
Span('已经绑定')
Span(`${this.listDataArr.length}`)
.fontColor(Color.Red)
Span('条: ')
}
.width('100%')
.margin({ top: 15 })
.padding({ left: 50 })
.fontSize(20)
.fontWeight(600)
}
.width('100%')
.padding({ top: 15, bottom: 10 })
Column() {
Row() {
Column() {
CheckboxGroup({ group: 'checkboxGroup' })
.checkboxShape(CheckBoxShape.ROUNDED_SQUARE)
.height(16)
.aspectRatio(1)
.selectAll($$this.isSelectedAll)
}
.width(40)
Text('编码')
.layoutWeight(1)
.fontSize(24)
.textAlign(TextAlign.Center)
.border({ width: { left: 1, right: 1 } })
.padding({ top: 5, bottom: 5 })
Text('名称')
.layoutWeight(1)
.fontSize(24)
.textAlign(TextAlign.Center)
.padding({ top: 5, bottom: 5 })
}
.width('100%')
.border({ width: { bottom: 1 } })
.backgroundColor('#E4EAFF')
List() {
ForEach(this.listDataArr, (item: ICodeAndName, index: number) => {
ListItem() {
Row() {
Row() {
Checkbox({ group: 'checkboxGroup' })
.shape(CheckBoxShape.ROUNDED_SQUARE)
.height(16)
.aspectRatio(1)
.select(item.isSelected)
.onChange(() => {
if (this.listDataArr[index]) {
this.listDataArr[index].isSelected = !item.isSelected
}
})
}
.justifyContent(FlexAlign.Center)
.width(40)
Row() {
Text(item.code)
.layoutWeight(1)
.fontSize(19)
.textAlign(TextAlign.Center)
.border({ width: { left: 1, right: 1 } })
.padding({
top: 6,
bottom: 6,
left: 4,
right: 4
})
Text(item.name)
.layoutWeight(1)
.fontSize(19)
.textAlign(TextAlign.Center)
.padding({
top: 6,
bottom: 6,
left: 4,
right: 4
})
}
.layoutWeight(1)
}
.width('100%')
.border({ width: { bottom: 1 } })
}
}, (item: ICodeAndName) => item.code)
}
.width('100%')
.layoutWeight(1)
}
.width('95%')
.layoutWeight(1)
.border({ width: 1 })
.margin({ top: 10, bottom: 10 })
Row() {
Text('清除')
.buttonExtend()
.onClick(() => {
this.clear()
})
Text('提交')
.buttonExtend()
.onClick(() => {
})
}
.width('100%')
.padding({ left: 40, right: 40 })
.justifyContent(FlexAlign.SpaceBetween)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F9')
.padding({ bottom: 20 })
}
}
@Extend(Text)
function buttonExtend() {
.width(100)
.height(35)
.textAlign(TextAlign.Center)
.backgroundColor('#126DDE')
.fontSize(20)
.fontColor('#fff')
.borderRadius(5)
}
更多关于HarmonyOS鸿蒙Next中@State装饰器,置空数据后,打印显示为空,但是界面还是留有数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
主要是修改了这一行代码: this.listDataArr[index].isSelected = !item.isSelected
不过这样onChange的时候,还是会报错,毕竟你已经把所有数据都删除了,是找不到this.listDataArr[index]数据项的,需要增加一点安全校验哦!,
if (this.listDataArr[index]) {
this.listDataArr[index].isSelected = !item.isSelected
}
还有一个办法
CheckboxGroup({ group: 'checkboxGroup' })
.checkboxShape(CheckBoxShape.ROUNDED_SQUARE)
.height(16)
.aspectRatio(1)
// .selectAll(this.isSelectedAll)
.onClick(()=>{
this.isSelectedAll = !this.isSelectedAll
})
这个不行,我刚试了。我在多选框加了条件判断,然后可以了,但是我不理解,
啊,我这里可以啊……,
我重新复制代码在模拟器跑了下,也可以了。。。。,
if (i.index === 1) {
if (this.isSelectedAll) {
this.isSelectedAll = false;
setTimeout(()=>{
this.listDataArr = [];
console.log(JSON.stringify(this.listDataArr))
},10)
}
}
这么写就可以了
没太懂为啥要加个延时器来造异步,
emmmm因为你这里是多选框……反正你就这么写就可以了,
可能组件缓存导致残留**,**List/ForEach 组件可能因复用机制保留旧节点。需通过 if 条件渲染 或 visibility 属性 显式控制显隐:
// 方案1:if 条件控制(完全移除节点)
if (this.dataList.length > 0) {
List() {
ForEach(this.dataList, ...)
}
} else {
Text('空状态提示')
}
// 方案2:visibility 控制(保留布局占位)
List()
.visibility(this.dataList.length > 0 ? Visibility.Visible : Visibility.None)
没作用,
@State装饰器在鸿蒙Next中置空数据后界面仍显示旧数据,是因为UI更新机制基于状态变更检测。当数据被置空时,如果UI组件未触发重新渲染,可能仍保留之前的状态缓存。需要确保数据变更后触发UI刷新,例如通过修改状态变量或调用相关更新方法。
这个问题是由于在同一个UI更新周期内,连续修改两个@State变量时,ArkUI框架的更新机制导致的。
根本原因分析:
-
@State变量的更新机制:当@State变量被修改时,ArkUI会触发UI重新渲染。但多个@State变量的修改如果在同一个微任务周期内,框架可能会进行批量更新优化。 -
代码执行顺序问题:
this.listDataArr = [] // ① 清空数组 this.isSelectedAll = false // ② 修改全选状态当执行这两行代码时,ArkUI检测到
listDataArr的变化,会触发ForEach重新渲染。但由于isSelectedAll也在同一周期被修改,框架可能将这两个更新合并处理。 -
CheckboxGroup的
selectAll绑定:CheckboxGroup的selectAll($$this.isSelectedAll)绑定了isSelectedAll状态。当isSelectedAll被设置为false时,CheckboxGroup会尝试取消所有复选框的选中状态。 -
竞态条件:在ForEach基于空数组重新渲染的同时,CheckboxGroup正在尝试取消选中已经不存在的复选框项,这可能导致UI状态不一致。
解决方案:
将两个状态更新分开到不同的执行周期:
if (this.isSelectedAll) {
this.listDataArr = []
console.log(JSON.stringify(this.listDataArr))
// 使用setTimeout或Promise将isSelectedAll的更新放到下一个微任务
setTimeout(() => {
this.isSelectedAll = false
}, 0)
// 或者使用Promise
// Promise.resolve().then(() => {
// this.isSelectedAll = false
// })
}
替代方案:
如果希望保持同步更新,可以调整代码逻辑顺序:
if (this.isSelectedAll) {
this.isSelectedAll = false // 先取消全选状态
this.listDataArr = [] // 再清空数组
console.log(JSON.stringify(this.listDataArr))
}
这样确保在清空数组前,CheckboxGroup已经处理完取消全选的逻辑,避免状态冲突。

