nextui-org / nextui

🚀 Beautiful, fast and modern React UI library.
https://nextui.org
MIT License
21.94k stars 1.53k forks source link

Table Scroll Position Reset After Data Refetch in Next.js App #3779

Closed dharmveer97 closed 1 month ago

dharmveer97 commented 1 month ago

NextUI Version

2.4.6

Describe the bug

I’m using the following dependencies in my Next.js application:

@nextui-org/react: ^2.4.6 react: 18.2.0 next: ^14.2.3

I have a table from Next UI inside a modal that displays data, with a form to schedule orders. When new data is submitted, the table fetches the updated data using refetch. The issue is that after refetching, the table automatically scrolls to the top instead of staying at the scroll position where the new data was added. This causes a poor user experience since the table loses the user's current scroll location after each data update.

Steps to Reproduce the Bug or Issue

  1. Implement a table using @nextui-org/react with data populated from an API.
  2. Include a form within the table (or modal) to submit new data.
  3. Upon submitting, trigger a refetch to get updated data.
  4. Observe that the table scroll position resets to the top after refetching.

Expected behavior

After submitting data and refetching, the table should maintain its current scroll position, so the user doesn't have to manually scroll down to find the newly added data in the center or anywhere.

Screenshots or Videos

Screen Recording 2024-09-19 at 3.36.46 AM 2 (1).mov.zip

Operating System Version

MacOS Sanoma 14.6.1

Browser

Edge

linear[bot] commented 1 month ago

ENG-1372 Table Scroll Position Reset After Data Refetch in Next.js App

dharmveer97 commented 1 month ago
import { Table } from '@nextui-org/react';

const TableGroup = ({
  children,
  bottomContent,
  topContent,
  sortDescriptor,
  setSortDescriptor,
  onRowAction,
  ...props
}) => (
  <Table
    {...props}
    aria-label="table with custom cells, pagination and sorting"
    isHeaderSticky
    bottomContentPlacement="outside"
    classNames={{
      wrapper: 'max-h-[382px] md:max-h-[67vh]',
    }}
    onRowAction={onRowAction}
    topContentPlacement="outside"
    bottomContent={bottomContent}
    sortDescriptor={sortDescriptor}
    topContent={topContent}
    onSortChange={setSortDescriptor}
  >
    {children}
  </Table>
);

export default TableGroup;

'use client';

import {
  TableHeader,
  TableColumn,
  TableBody,
  TableRow,
  TableCell,
} from '@nextui-org/react';
import { useState } from 'react';
import { Table, Loading } from '../elements';
import TableCellRenderer from './TableCell';

function OrderTable({
  loading,
  user,
  search,
  allOrders,
  filteredColumns,
  handleRemoveOrder,
  handleRowLink,
  refetch,
}) {
  const [selectedKeys, setSelectedKeys] = useState([]);
  const handleSelectRowChange = (selectedRows) => {
    setSelectedKeys(selectedRows);
  };

  return (
    <Table
      hideHeader={loading}
      // bottomContent={allOrders?.length > 0 ? '' : ''}
      aria-label="All orders table"
      color="primary"
      selectedKeys={selectedKeys}
      selectionMode="single"
      onSelectionChange={handleSelectRowChange}
      onRowAction={(key) => {
        handleRowLink(key);
      }}
    >
      <TableHeader columns={filteredColumns}>
        {(column) => (
          <TableColumn
            key={column.uid}
            align={column.uid === 'actions' ? 'end' : 'start'}
            allowsSorting={column.sortable}
          >
            {column.name}
          </TableColumn>
        )}
      </TableHeader>

      <TableBody
        loadingContent={<Loading />}
        isLoading={!!loading}
        emptyContent={
          !loading && allOrders?.length < 1 && search
            ? `There are no orders that match ${search || ''}`
            : 'No Data found'
        }
        items={allOrders}
      >
        {(item) => (
          <TableRow key={item.id} className="cursor-pointer">
            {(columnKey) => (
              <TableCell>
                <TableCellRenderer
                  order={item}
                  columnKey={columnKey}
                  user={user}
                  handleRemoveOrder={handleRemoveOrder}
                  refetch={refetch}
                />
              </TableCell>
            )}
          </TableRow>
        )}
      </TableBody>
    </Table>
  );
}

export default OrderTable;
wingkwong commented 1 month ago

can you also test once in 2.4.8 to see if it is still reproducible?

dharmveer97 commented 1 month ago

can you also test once in 2.4.8 to see if it is still reproducible?

yes same issue "@nextui-org/react": "^2.4.8",

dharmveer97 commented 1 month ago

https://github.com/user-attachments/assets/3549bc30-d1dd-4578-95a6-3ec0f151e09d

dharmveer97 commented 1 month ago

@wingkwong

wingkwong commented 1 month ago

Please share a sandbox instead. It's hard to debug just based on the given code.

dharmveer97 commented 1 month ago

https://codesandbox.io/p/github/dharmveer97/nextui-table-exploration/main?import=true @wingkwong

https://github.com/dharmveer97/nextui-table-exploration

dharmveer97 commented 1 month ago

Steps

  1. Wait for Data Load: Ensure all data is fully loaded from the server API before proceeding.
  2. Scroll to Bottom: Once the data has been loaded, scroll to the bottom of the screen.
  3. Click 'Add New Entry': Press the "Add New Entry" button.
  4. Enter Data: Input data using ID 1, provide any name, and set the status.
  5. Prevent Auto-Scroll: Ensure the table maintains its scroll position and does not reset to the top after adding the entry.

Make sure you scroll a little bit bottom before putting any details.

FormData = ID 1 Name: ANY Name, Status: ANY

dharmveer97 commented 1 month ago

https://github.com/user-attachments/assets/178969c1-a9d4-40ae-89a6-195c8819fe3c

dharmveer97 commented 1 month ago

Hi @wingkwong, could you please make this issue reproducible?

wingkwong commented 1 month ago

@dharmveer97 your sandbox is not reproducible at all. you don't need to use apollo but some mock data to reproduce. please make it as minimal as possible.