diff --git a/packages/components/table/__tests__/table-column.test.ts b/packages/components/table/__tests__/table-column.test.ts
index b5d7d14deb..06d3bcd737 100644
--- a/packages/components/table/__tests__/table-column.test.ts
+++ b/packages/components/table/__tests__/table-column.test.ts
@@ -338,6 +338,92 @@ describe('table column', () => {
expect(expectIndexs).toEqual(actualIndexs)
expect(wrapper.vm.selected.length).toBe(wrapper.vm.testData.length)
})
+
+ // #20292
+ it('Maintain child selection states during data updates', async () => {
+ const wrapper = mount({
+ components: {
+ ElTable,
+ ElTableColumn,
+ },
+ template: `
+
+
+
+
+ `,
+
+ data() {
+ return {
+ testData: [
+ { id: 0, desc: 'record 1' },
+ { id: 1, desc: 'record 2' },
+ {
+ id: 2,
+ desc: 'record 3',
+ children: [
+ { id: 3, desc: 'record 3-1' },
+ { id: 4, desc: 'record 3-2' },
+ ],
+ },
+ ],
+ }
+ },
+ methods: {
+ addRow() {
+ this.testData.push({ id: 5, desc: 'record 4' })
+ },
+ removeRow() {
+ this.testData.pop()
+ },
+ removeChildRow() {
+ this.testData[2].children.pop()
+ },
+ },
+ })
+ await doubleWait()
+
+ const getSelection = wrapper.vm.$refs.tableRef.getSelectionRows
+ const domArr = wrapper.findAll('.el-table__row .el-checkbox')
+
+ let selectionKeys = []
+
+ domArr.forEach(
+ (checkbox, index) => index < 3 && checkbox.trigger('click')
+ )
+ await doubleWait()
+
+ selectionKeys = getSelection().map((item) => item.id)
+ expect(selectionKeys).toEqual([0, 1, 2, 3, 4])
+
+ // add
+ wrapper.vm.addRow()
+ await doubleWait()
+
+ selectionKeys = getSelection().map((item) => item.id)
+ expect(selectionKeys).toEqual([0, 1, 2, 3, 4])
+
+ // remove
+ wrapper.vm.removeRow()
+ await doubleWait()
+
+ selectionKeys = getSelection().map((item) => item.id)
+ expect(selectionKeys).toEqual([0, 1, 2, 3, 4])
+
+ // remove child
+ wrapper.vm.removeChildRow()
+ await doubleWait()
+
+ selectionKeys = getSelection().map((item) => item.id)
+ expect(selectionKeys).toEqual([0, 1, 2, 3])
+
+ // remove with child
+ wrapper.vm.removeRow()
+ await doubleWait()
+
+ selectionKeys = getSelection().map((item) => item.id)
+ expect(selectionKeys).toEqual([0, 1])
+ })
})
describe('= index', () => {
diff --git a/packages/components/table/src/store/watcher.ts b/packages/components/table/src/store/watcher.ts
index 664b2ccd3c..a6dd42e4c0 100644
--- a/packages/components/table/src/store/watcher.ts
+++ b/packages/components/table/src/store/watcher.ts
@@ -193,7 +193,8 @@ function useWatcher() {
let deleted
if (rowKey.value) {
deleted = []
- const dataMap = getKeysMap(data.value, rowKey.value)
+ const childrenKey = instance?.store?.states?.childrenColumnName.value
+ const dataMap = getKeysMap(data.value, rowKey.value, true, childrenKey)
for (const key in selectedMap.value) {
if (hasOwn(selectedMap.value, key) && !dataMap[key]) {
deleted.push(selectedMap.value[key].row)
diff --git a/packages/components/table/src/util.ts b/packages/components/table/src/util.ts
index 315730f9ce..878e0c22ee 100644
--- a/packages/components/table/src/util.ts
+++ b/packages/components/table/src/util.ts
@@ -196,12 +196,24 @@ export const getRowIdentity = (
export const getKeysMap = function (
array: T[],
- rowKey: string
+ rowKey: string,
+ flatten = false,
+ childrenKey = 'children'
): Record {
+ const data = array || []
const arrayMap = {}
- ;(array || []).forEach((row, index) => {
+
+ data.forEach((row, index) => {
arrayMap[getRowIdentity(row, rowKey)] = { row, index }
+
+ if (flatten) {
+ const children = row[childrenKey]
+ if (isArray(children)) {
+ Object.assign(arrayMap, getKeysMap(children, rowKey, true, childrenKey))
+ }
+ }
})
+
return arrayMap
}