Skip to content

Commit

Permalink
fix: Set initial data in useTable state
Browse files Browse the repository at this point in the history
* Fix flickering between 'No data' state on first render, before
  `updateData` useEffect fires.
  • Loading branch information
kiosion committed Nov 13, 2024
1 parent bb8c2f3 commit f2782ce
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 35 deletions.
95 changes: 60 additions & 35 deletions web/packages/design/src/DataTable/useTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,46 +42,71 @@ export default function useTable<T>({
disableFilter = false,
...props
}: TableProps<T>) {
const [state, setState] = useState<{
data: T[];
searchValue: string;
sort?: Sort<T>;
pagination?: Pagination<T>;
}>(() => {
// Determine the initial sort
let initialSort: Sort<T> | undefined;
if (!customSort) {
const { initialSort: initialSortProp } = props;
// Finds the first sortable column to use for the initial sorting
let col: TableColumn<T> | undefined;
if (!customSort) {
const { initialSort } = props;
if (initialSort) {
col = initialSort.altSortKey
? columns.find(col => col.altSortKey === initialSort.altSortKey)
: columns.find(col => col.key === initialSort.key);
} else {
col = columns.find(column => column.isSortable);
}
if (initialSortProp) {
col = initialSortProp.altSortKey
? columns.find(col => col.altSortKey === initialSortProp.altSortKey)
: columns.find(col => col.key === initialSortProp.key);
} else {
col = columns.find(column => column.isSortable);
}
if (col) {
initialSort = {
key: (col.altSortKey || col.key) as keyof T,
onSort: col.onSort,
dir: initialSortProp?.dir || 'ASC',
};
}
}

return {
data: [],
searchValue: clientSearch?.initialSearchValue || '',
sort: col
? {
key: (col.altSortKey || col.key) as keyof T,
onSort: col.onSort,
dir: props.initialSort?.dir || 'ASC',
}
: undefined,
pagination: pagination
? {
paginatedData: paginateData([], pagination.pageSize),
currentPage: 0,
pagerPosition: pagination.pagerPosition,
pageSize: pagination.pageSize || 15,
CustomTable: pagination.CustomTable,
}
: undefined,
// Compute the initial data
const initialSearchValue = clientSearch?.initialSearchValue || '';
let initialData: T[];
if (serversideProps || disableFilter || !data?.length) {
initialData = data || [];
} else {
initialData = sortAndFilter(
data,
initialSearchValue,
initialSort,
searchableProps ||
(columns
.filter(column => column.key)
.map(column => column.key) as (keyof T & string)[]),
searchAndFilterCb,
showFirst
);
}

// Compute initial pagination if applicable
let initialPagination: Pagination<T> | undefined;
if (pagination) {
const pages = paginateData(initialData, pagination.pageSize);
initialPagination = {
paginatedData: pages,
currentPage: 0,
pagerPosition: pagination.pagerPosition,
pageSize: pagination.pageSize || 15,
CustomTable: pagination.CustomTable,
};
});
}

const [state, setState] = useState<{
data: T[];
searchValue: string;
sort?: Sort<T>;
pagination?: Pagination<T>;
}>(() => ({
data: initialData,
searchValue: initialSearchValue,
sort: initialSort,
pagination: initialPagination,
}));

function searchAndFilterCb(
targetValue: any,
Expand Down
6 changes: 6 additions & 0 deletions web/packages/teleport/src/JoinTokens/JoinTokens.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ describe('JoinTokens', () => {
render(<Component />);
const optionButtons = await screen.findAllByText(/options/i);
await userEvent.click(optionButtons[0]);
// TODO(kiosion): What's happening here is that DataTable re-renders faster than `userEvent.click` can be fired, so the button ref is stale.
// This wasn't an issue prior since DataTable used to init with no data regardless of what was passed in,
// so 'findAllByText' would wait a few ms before finding the text on commit 2.
// Querying and clicking a second time works but there's definitely a better way to handle this.
const _optionButtons = screen.getAllByText(/options/i);
await userEvent.click(_optionButtons[0]);
const editButtons = await screen.findAllByText(/view\/edit/i);
await userEvent.click(editButtons[0]);
expect(screen.getByText(/edit token/i)).toBeInTheDocument();
Expand Down

0 comments on commit f2782ce

Please sign in to comment.