1

I am newbie to react-table, having started using it for a week now. I was able to get the table rows and also infinite scrolling working.

However, when I click on the delete icon in a row, the table becomes empty. From the web inspector, I can see that the useState variable listInfo (which holds the data in listinfo.data has become an empty array, and all other state varaiables such as count and totalcount have also been reset.

Perhaps this has got something to do with the useMemo, may be. I couldn't create a codesandbox or stackblitz based working application, as I am running into some other problems such as 'React undefined'.

Here is the screenshot of the behavior.. Before clicking delete icon: enter image description here

After clicking delete icon: enter image description here Here are the important bits of code:

1. Component Defintion and state variables...
    14  export default function DataTable(props) {
    15  
    16    const {
    17      fetcher,  // A query fn to fetch the item list
    18      onEdit,   // a callback fn that will be called (generally for saving the modified item) when user edits an item 
    19      onDelete  // a callback fn to delete the selected item
    20    } = props;
    21  
    22    // State manager for delete confirmation
    23    //const [showConfirm, setShowConfirm] = useState({productId:null, show:false})
    24    const [listInfo, setListInfo] = useState({
    25      data: [], 
    26      error: null,
    27      shouldFetch: false,
    28      showConfirm: false,
    29      onDeleteConfirm: onDelete,
    30      onEdit: onEdit,
    31      selectedItem: null,
    32      totalCount: 0,
    33      currentCount: 0,
    34      pageIndex:1
    35    })

2. columns definition like below...
    47    //TODO: Column definitions can come from props, as they
    48    // may vary from case to case.
    49    const columns = useMemo(() => ([
    50      {
    51        Header: "Image",
    52        accessor: "imageUrl",
    53        Cell: ({value}) => <img src={value} width={50}/>
    54      },
    55      {
    56        Header: "Product Name",
    57        accessor: "name",
    58        minWidth: 600,
    59      },
    60      {
    61        Header: "M.R.P", 
    62        accessor: "price",
    63        Cell: row => <span><FontAwesomeIcon icon={solid('indian-rupee-sign')} /> {parseFloat(row.value).toFixed((2))} </span>,
    64        minWidth:200
    65      },
    66      {
    67        Header: "Suggested Selling Price",
    68        accessor: "onSalePrice",
    69        Cell: row => <><FontAwesomeIcon icon={solid('indian-rupee-sign')} /> {parseFloat(row.value).toFixed((2))} </>,
    70        minWidth:200
    71      }
    72    ]), [])
3. Fetching data using react-query...
    82    const {status, data:listData, error} = useQuery([fetcher.key, fetcher.args, listInfo.pageIndex, PAGE_SIZE ], fetcher.fn, {enabled:listInfo.shouldFetch} )
    83    switch (status) {
    84      case 'idle': break;
    85      case 'loading': break;
    86      case 'success':
    87        debugger
    88        if (listInfo.shouldFetch) {
    89          let incomingData = listData['supplier']['products']
    90          if (listInfo.pageIndex === 1) {
    91            setListInfo({...listInfo, 
    92              data:incomingData, 
    93              currentCount:incomingData.length, 
    94              totalCount:listData?.totalProducts || incomingData.length,
    95              shouldFetch:false})
    96          } else { // if page index > 1, means, we are geting additional data for subsequent 
    97            let newData = listInfo.data.concat(incomingData)
    98            setListInfo({...listInfo, 
    99              data:newData, 
   100              currentCount: newData.length,
   101              totalCount: listData?.totalProducts || incomingData.length,
   102              shouldFetch:false})
   103          }
   104        }
   105        break;
   106      case 'error':
   107        if (listInfo.shouldFetch)
   108          setListInfo({...listInfo, shouldFetch:false})
   109        break;
   110  
   111      default:
   112        throw new Error({message: 'Unknown status', code: -1})
   113    }

4. Added Tablehooks for icons display for each row.
   129    const tableHooks = (hooks) => {
   130      hooks.visibleColumns.push((columns) => [
   131        ...columns,
   132        {
   133          id:"Edit",
   134          Header: "Filter",
   135          Cell: ({row}) => (
   136            <Button onClick={() => { 
   137              debugger
   138              onEdit(row.original.id)}}>
   139              Edit 
   140            </Button>
   141          )
   142        },
   143        {
   144          id: "Delete",
   145          Cell: ({row}) => (
   146            <span className='icon is-small mr-3'>
   147              <FontAwesomeIcon 
   148                onClick={() => {
   149                  console.log('listinfo:', listInfo)
   150                  /*
   151                    setListInfo({...listInfo, 
   152                                    showConfirm:true, 
   153                                    selectedProduct: row.original})
   154                                    */
   155                }}
   156                icon={regular('trash-can')} 
   157                color='red' 
   158                size='lg' 
   159              />
   160              </span>
   161          )
   162        }
   163      ])
   164    }
   165  
   166    const tableInstance = useTable({columns, data }, tableHooks)

5. Finally, the table markup
   168    const  {
   169      getTableProps,
   170      getTableBodyProps,
   171      headerGroups,
   172      rows,
   173      prepareRow
   174    } = tableInstance;
   175  
   176    console.log("List Info, before markup:", listInfo)
   177    return (
   178      <>
   179      <InfiniteScroll
   180        dataLength={rows.length}
   181        next={fetchNext}
   182        hasMore={listInfo.currentCount < listInfo.totalCount}
   183        loader={<h4>Loading...</h4>}
   184        endMessage="End of data."
   185        height={1488}
   186      >
   187        <Table className='is-fullwidth' {...getTableProps()}>
   188          <thead>
   189            {headerGroups.map((headerGroup,) => (
   190              <tr {...headerGroup.getHeaderGroupProps()}>
   191                {headerGroup.headers.map((column) => (
   192                  <th {...column.getHeaderProps()}> {column.render("Header")} </th>
   193                ))}
   194              </tr>
   195            ))}
   196          </thead>
   197          <tbody {...getTableBodyProps()}>
   198            {rows.map((row) => {
   199              prepareRow(row)
   200              return (
   201            <tr {...row.getRowProps()}>
   202                {row.cells.map(cell =>{
   203                  return (
   204                    <td {...cell.getCellProps()}> {cell.render('Cell') } </td>
   205                  )
   206                  })}
   207                </tr>
   208              )
   209            })}
   210          </tbody>
   211        </Table>
   212      </InfiniteScroll>
   213      {
   214        listInfo.showConfirm
   215              ? <Dialog message={`Delete the item (${listInfo.selectedProduct.name})`}
   216                    title="Delete Product"
   217                    yesBtn='Yes'
   218                    noBtn='No'
   219                    onConfirm={deleteProductYes}
   220                    onReject={deleteProductNo}   
   221                    visible={true}
   222                    setVisible={()=>setListInfo({...listInfo, showConfirm:false})} />
   223              : null
   224      }
   225        </>
   226    )

I have tried memoizing (and also not using memoize) for data. But still, the behaviour is inconsistent. First time, I launch the code it works fine (with data being intact). Once I refresh and reload the page, and then I click the row icon, the data is reset.

May be I am doing some silly mistake here, but unable to detect it. Some clues might help me here.

Mopparthy Ravindranath
  • 3,014
  • 6
  • 41
  • 78
  • Just browsing through it, but I think it'd really help you narrow down what is going wrong is if you separated `listInfo` into different state variables instead of keeping it all as a single item. Something somewhere is getting a stale copy of `listInfo` and overwriting `listInfo.data` with a blank array, is my guess. Or, maybe you could use the callback version of `setListInfo`? `setListInfo((prevState) => { ...prevState, fieldToUpdate: updated })` etc – toki Mar 09 '22 at 04:46
  • Yes, I did exactly that. It is working fine now. But this experience of 2 days shows to me that I have a lot to learn about react-query. – Mopparthy Ravindranath Mar 09 '22 at 13:38
  • In fact, now I ended up, not using react-query, in this use case and just a simple fetch function triggered from useEffect. – Mopparthy Ravindranath Mar 09 '22 at 13:39

0 Answers0