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:
After clicking delete icon:
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.