Skip to content

Commit

Permalink
fixup: avoid calls to setState on initial render
Browse files Browse the repository at this point in the history
  • Loading branch information
bwittenberg committed Jun 4, 2024
1 parent ff47283 commit ed06916
Showing 1 changed file with 76 additions and 69 deletions.
145 changes: 76 additions & 69 deletions packages/react/src/DataTable/useTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ export function useTable<Data extends UniqueRow>({
initialSortColumn,
initialSortDirection,
}: TableConfig<Data>): Table<Data> {
const [rowOrder, setRowOrder] = useState(data)
const [prevData, setPrevData] = useState<typeof data | null>(null)
const [prevData, setPrevData] = useState(data)
const [prevColumns, setPrevColumns] = useState(columns)
const [sortByColumn, setSortByColumn] = useState<ColumnSortState>(() => {
return getInitialSortState(columns, initialSortColumn, initialSortDirection)
Expand Down Expand Up @@ -93,12 +92,14 @@ export function useTable<Data extends UniqueRow>({
}
})

const [sortedData, setSortedData] = useState(sortByColumn ? sortData({data, state: sortByColumn, headers}) : data)

// Update the row order and apply the current sort column to the incoming data
if (data !== prevData) {
setPrevData(data)
setRowOrder(data)
setSortedData(data)
if (sortByColumn) {
sortRows(sortByColumn)
setSortedData(sortData({data, state: sortByColumn, headers}))
}
}

Expand All @@ -112,75 +113,12 @@ export function useTable<Data extends UniqueRow>({
sortByColumn && sortByColumn.id === header.id ? transition(sortByColumn.direction) : DEFAULT_SORT_DIRECTION,
}
setSortByColumn(sortState)
sortRows(sortState)
}

/**
* Sort the rows of a table with the given column sort state. If the data in the table is sparse,
* blank values will be ordered last regardless of the sort direction.
*/
function sortRows(state: Exclude<ColumnSortState, null>) {
const header = headers.find(header => {
return header.id === state.id
})
if (!header) {
throw new Error(`Unable to find header with id: ${state.id}`)
}

if (header.column.sortBy === false || header.column.sortBy === undefined) {
throw new Error(`The column for this header is not sortable`)
}

const sortMethod =
header.column.sortBy === true
? strategies.basic
: typeof header.column.sortBy === 'string'
? strategies[header.column.sortBy]
: header.column.sortBy

setRowOrder(rowOrder => {
return rowOrder.slice().sort((a, b) => {
if (header.column.field === undefined) {
return 0
}

// Custom sort functions operate on the row versus the field
if (typeof header.column.sortBy === 'function') {
if (state.direction === SortDirection.ASC) {
// @ts-ignore todo
return sortMethod(a, b)
}
// @ts-ignore todo
return sortMethod(b, a)
}

const valueA = get(a, header.column.field)
const valueB = get(b, header.column.field)

if (valueA && valueB) {
if (state.direction === SortDirection.ASC) {
// @ts-ignore todo
return sortMethod(valueA, valueB)
}
// @ts-ignore todo
return sortMethod(valueB, valueA)
}

if (valueA) {
return -1
}

if (valueB) {
return 1
}
return 0
})
})
setSortedData(sortData({data, state: sortState, headers}))
}

return {
headers,
rows: rowOrder.map(row => {
rows: sortedData.map(row => {
return {
id: `${row.id}`,
getValue() {
Expand Down Expand Up @@ -210,6 +148,75 @@ export function useTable<Data extends UniqueRow>({
}
}

/**
* Sort the rows of a table with the given column sort state. If the data in the table is sparse,
* blank values will be ordered last regardless of the sort direction.
*/
function sortData<Data extends UniqueRow>({
data,
state,
headers,
}: {
data: Data[]
state: Exclude<ColumnSortState, null>
headers: Header<Data>[]
}) {
const header = headers.find(header => {
return header.id === state.id
})
if (!header) {
throw new Error(`Unable to find header with id: ${state.id}`)
}

if (header.column.sortBy === false || header.column.sortBy === undefined) {
throw new Error(`The column for this header is not sortable`)
}

const sortMethod =
header.column.sortBy === true
? strategies.basic
: typeof header.column.sortBy === 'string'
? strategies[header.column.sortBy]
: header.column.sortBy

return data.slice().sort((a, b) => {
if (header.column.field === undefined) {
return 0
}

// Custom sort functions operate on the row versus the field
if (typeof header.column.sortBy === 'function') {
if (state.direction === SortDirection.ASC) {
// @ts-ignore todo
return sortMethod(a, b)
}
// @ts-ignore todo
return sortMethod(b, a)
}

const valueA = get(a, header.column.field)
const valueB = get(b, header.column.field)

if (valueA && valueB) {
if (state.direction === SortDirection.ASC) {
// @ts-ignore todo
return sortMethod(valueA, valueB)
}
// @ts-ignore todo
return sortMethod(valueB, valueA)
}

if (valueA) {
return -1
}

if (valueB) {
return 1
}
return 0
})
}

function getInitialSortState<Data extends UniqueRow>(
columns: Array<Column<Data>>,
initialSortColumn?: string | number,
Expand Down

0 comments on commit ed06916

Please sign in to comment.