Skip to content

Commit 129fadf

Browse files
fix: wires up abort controller logic for list columns (#9180)
### What? List column state could become out of sync if toggling columns happened in rapid succession as seen in CI. Or when using a spotty connection where responses could come back out of order. ### Why? State was not being preserved between toggles. Leading to incorrect columns being toggled on/off. ### How? Updates internal column state before making the request to the server so when a future toggle occurs it has up to date state of all columns. Also introduces an abort controller to prevent the out of order response issue.
1 parent cea7d58 commit 129fadf

File tree

1 file changed

+61
-12
lines changed
  • packages/ui/src/elements/TableColumns

1 file changed

+61
-12
lines changed

packages/ui/src/elements/TableColumns/index.tsx

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { Column } from '../Table/index.js'
1010
import { useConfig } from '../../providers/Config/index.js'
1111
import { usePreferences } from '../../providers/Preferences/index.js'
1212
import { useServerFunctions } from '../../providers/ServerFunctions/index.js'
13+
import { abortAndIgnore } from '../../utilities/abortAndIgnore.js'
1314

1415
export interface ITableColumns {
1516
columns: Column[]
@@ -77,25 +78,36 @@ export const TableColumnsProvider: React.FC<Props> = ({
7778
const { getPreference, setPreference } = usePreferences()
7879

7980
const [tableColumns, setTableColumns] = React.useState(columnState)
81+
const tableStateControllerRef = React.useRef<AbortController>(null)
8082

8183
const moveColumn = useCallback(
8284
async (args: { fromIndex: number; toIndex: number }) => {
85+
abortAndIgnore(tableStateControllerRef.current)
86+
8387
const { fromIndex, toIndex } = args
8488
const withMovedColumn = [...tableColumns]
8589
const [columnToMove] = withMovedColumn.splice(fromIndex, 1)
8690
withMovedColumn.splice(toIndex, 0, columnToMove)
8791

88-
const { state: columnState, Table } = await getTableState({
92+
setTableColumns(withMovedColumn)
93+
94+
const controller = new AbortController()
95+
tableStateControllerRef.current = controller
96+
97+
const result = await getTableState({
8998
collectionSlug,
9099
columns: sanitizeColumns(withMovedColumn),
91100
docs,
92101
enableRowSelections,
93102
renderRowTypes,
103+
signal: controller.signal,
94104
tableAppearance,
95105
})
96106

97-
setTableColumns(columnState)
98-
setTable(Table)
107+
if (result) {
108+
setTableColumns(result.state)
109+
setTable(result.Table)
110+
}
99111
},
100112
[
101113
tableColumns,
@@ -111,24 +123,55 @@ export const TableColumnsProvider: React.FC<Props> = ({
111123

112124
const toggleColumn = useCallback(
113125
async (column: string) => {
114-
const toggledColumns: Pick<Column, 'accessor' | 'active'>[] = tableColumns.map((col) => {
115-
return {
116-
accessor: col.accessor,
117-
active: col.accessor === column ? !col.active : col.active,
118-
}
119-
})
126+
abortAndIgnore(tableStateControllerRef.current)
127+
128+
const { newColumnState, toggledColumns } = tableColumns.reduce<{
129+
newColumnState: Column[]
130+
toggledColumns: Pick<Column, 'accessor' | 'active'>[]
131+
}>(
132+
(acc, col) => {
133+
if (col.accessor === column) {
134+
acc.newColumnState.push({
135+
...col,
136+
accessor: col.accessor,
137+
active: !col.active,
138+
})
139+
acc.toggledColumns.push({
140+
accessor: col.accessor,
141+
active: !col.active,
142+
})
143+
} else {
144+
acc.newColumnState.push(col)
145+
acc.toggledColumns.push({
146+
accessor: col.accessor,
147+
active: col.active,
148+
})
149+
}
120150

121-
const { state: columnState, Table } = await getTableState({
151+
return acc
152+
},
153+
{ newColumnState: [], toggledColumns: [] },
154+
)
155+
156+
setTableColumns(newColumnState)
157+
158+
const controller = new AbortController()
159+
tableStateControllerRef.current = controller
160+
161+
const result = await getTableState({
122162
collectionSlug,
123163
columns: toggledColumns,
124164
docs,
125165
enableRowSelections,
126166
renderRowTypes,
167+
signal: controller.signal,
127168
tableAppearance,
128169
})
129170

130-
setTableColumns(columnState)
131-
setTable(Table)
171+
if (result) {
172+
setTableColumns(result.state)
173+
setTable(result.Table)
174+
}
132175
},
133176
[
134177
tableColumns,
@@ -233,6 +276,12 @@ export const TableColumnsProvider: React.FC<Props> = ({
233276
sortColumnProps,
234277
])
235278

279+
React.useEffect(() => {
280+
return () => {
281+
abortAndIgnore(tableStateControllerRef.current)
282+
}
283+
}, [])
284+
236285
return (
237286
<TableColumnContext.Provider
238287
value={{

0 commit comments

Comments
 (0)