Originally Post at: Metaphore - SCP and Issue on GitHub Metaphore Repository #8
The Back Story about this Metaphor
React Table Trigger Changed Without SWR
Metaphore story
I'm into the world of javascript and reactjs is absolutely nil! And I found react-table
from TanStack and it's really cool! That agnostic (What The Buff!)
And I'm trying to simplify my old way of working with jQuery
when I was almost sinking to the bottom of the ocean (Hypertext Preprocessor) and didn't find the light of JavaScript
as a complete combat tool more promising.
In jQuery I need to create a function to repeat the request and I trigger it from the targeted event and it's easy.
My question is how can I do the same thing but in react-table
by not using any other library.
And here's what happened:
1// file: components/TablePagination.js 2function TablePagination({ 3 columns, 4 data, 5 fetchData, 6 loading, 7 pageCount: controlledPageCount, 8 totalRow, 9 actions: Actions 10}) { 11 const { 12 getTableProps, 13 getTableBodyProps, 14 headerGroups, 15 prepareRow, 16 page, 17 canPreviousPage, 18 canNextPage, 19 pageOptions, 20 pageCount, 21 gotoPage, 22 nextPage, 23 previousPage, 24 setPageSize, 25 state: { pageIndex, pageSize, globalFilter, sortBy }, 26 preGlobalFilteredRows, 27 setGlobalFilter 28 } = useTable( 29 { 30 columns, 31 data, 32 manualPagination: true, 33 manualGlobalFilter: true, 34 manualSortBy: true, 35 initialState: { 36 pageIndex: 0, 37 pageSize: 10 38 }, // Pass our hoisted table state 39 pageCount: controlledPageCount, 40 autoResetSortBy: false, 41 autoResetExpanded: false, 42 autoResetPage: false 43 }, 44 useGlobalFilter, 45 useSortBy, 46 usePagination 47 ); 48 49 const GlobalFilter = ({ preGlobalFilteredRows, globalFilter, setGlobalFilter }) => { 50 const count = preGlobalFilteredRows 51 const [value, setValue] = React.useState(globalFilter) 52 const onChange = useAsyncDebounce(value => { 53 setGlobalFilter(value || undefined) 54 }, 700) 55 56 return ( 57 <div className={Actions !== undefined ? 'flex flex-row justify-between' : 'flex flex-col'}> 58 {Actions !== undefined ? (<Actions />) : null} 59 <input 60 value={value || ""} 61 onChange={e => { 62 setValue(e.target.value); 63 onChange(e.target.value); 64 }} 65 placeholder={`${count} records...`} 66 type="search" 67 className={`input input-bordered input-sm w-full max-w-xs focus:outline-0 mb-2 ${Actions !== undefined ? '' : 'self-end'}`} 68 /> 69 </div> 70 ) 71 } 72 73 React.useEffect(() => { 74 let search = globalFilter === undefined ? '' : globalFilter 75 fetchData(pageSize, pageIndex, search); 76 }, [fetchData, pageIndex, pageSize, globalFilter, sortBy]); 77 78 return ( 79 <> 80 <GlobalFilter 81 preGlobalFilteredRows={totalRow} 82 globalFilter={globalFilter} 83 setGlobalFilter={setGlobalFilter} 84 /> 85 <div className="overflow-x-auto"> 86 <table {...getTableProps()} className='table table-compact table-zebra w-full'> 87 <thead> 88 {headerGroups.map(headerGroup => ( 89 <tr {...headerGroup.getHeaderGroupProps()}> 90 {headerGroup.headers.map(column => ( 91 <th {...column.getHeaderProps(column.getSortByToggleProps())}> 92 <span> 93 {column.isSorted ? column.isSortedDesc ? <ArrowLongDownIcon className='h-4 w-4 inline mr-1' /> : <ArrowLongUpIcon className='h-4 w-4 inline mr-1' /> : <FunnelIcon className='h-4 w-4 inline mr-1' />} 94 </span> 95 {column.render('Header')} 96 </th> 97 ))} 98 </tr> 99 ))} 100 </thead> 101 <tbody {...getTableBodyProps()}> 102 {page.length > 0 ? page.map((row, i) => { 103 prepareRow(row) 104 return ( 105 <tr {...row.getRowProps()} className='hover'> 106 {row.cells.map(cell => { 107 return <td {...cell.getCellProps()}>{cell.render('Cell')}</td> 108 })} 109 </tr> 110 ) 111 }) : (<tr className='hover'> 112 <td colSpan={10000} className='text-center'>Data not found!</td> 113 </tr>)} 114 {loading ? ( 115 <tr> 116 <td colSpan="10000">Loading...</td> 117 </tr> 118 ) : null} 119 </tbody> 120 </table> 121 </div> 122 <div className="flex flex-row justify-between"> 123 <div className='mt-2'> 124 <span> 125 Halaman{' '} 126 <strong> 127 {pageIndex + 1} dari {pageOptions.length} 128 </strong>{' '} 129 Total <strong>{preGlobalFilteredRows.length}</strong>{' '} 130 </span> 131 <span> 132 | Lompat ke halaman:{' '} 133 <input 134 type="number" 135 defaultValue={pageIndex + 1} 136 onChange={e => { 137 const page = e.target.value ? Number(e.target.value) - 1 : 0 138 gotoPage(page) 139 }} 140 className="input input-bordered input-sm w-20 max-w-xs focus:outline-0" 141 /> 142 </span>{' '} 143 <select 144 value={pageSize} 145 onChange={e => { 146 setPageSize(Number(e.target.value)) 147 }} 148 className="select select-bordered select-sm w-30 max-w-xs focus:outline-0" 149 > 150 {[10, 20, 30, 40, 50].map(pageSize => ( 151 <option key={pageSize} value={pageSize}> 152 Tampilkan {pageSize} baris 153 </option> 154 ))} 155 </select> 156 </div> 157 <div className='mt-2'> 158 <button className='btn btn-xs' onClick={() => gotoPage(0)} disabled={!canPreviousPage}> 159 {'<<'} 160 </button>{' '} 161 <button className='btn btn-xs' onClick={() => previousPage()} disabled={!canPreviousPage}> 162 {'<'} 163 </button>{' '} 164 <button className='btn btn-xs' onClick={() => nextPage()} disabled={!canNextPage}> 165 {'>'} 166 </button>{' '} 167 <button className='btn btn-xs' onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}> 168 {'>>'} 169 </button>{' '} 170 </div> 171 </div> 172 </> 173 ); 174} 175 176export default TablePagination
What I really want is that when I update data from a modal component (child), I can trigger the previous component (parent) I have to refresh the data in the table after a data change.
1// file: pages/Example.js (parent) 2function Example() { 3 4 const [data, setData] = useState([]); 5 const [loading, setLoading] = useState(false) 6 const [pageCount, setPageCount] = useState(0) 7 const [totalRow, setTotalRow] = useState(0) 8 const [refresh, setRefresh] = useState(false) 9 10 const fetchData = useCallback(async (pageSize, pageIndex, search) => { 11 setLoading(true) 12 const queryOptions = { 13 page: pageIndex, 14 limit: pageSize, 15 search: search 16 } 17 const customers = await customerDatatable(queryOptions) 18 19 setData(customers.data) 20 setPageCount(customers.pagination.totalPage) 21 setTotalRow(customers.pagination.totalRow) 22 setLoading(false) 23 setRefresh(false) 24 }, [refresh]); 25 26 const columns = useMemo( 27 () => [ 28 ...., 29 { 30 Header: 'Actions', 31 accessor: (row) => { 32 return ( 33 <div className='flex flex-row w-38'> 34 <ReuseableModal modalId={`modalEdit-${row.customer_uuid}`} btnClassName={`btn-xs btn-info mr-2`} btnContent={<PencilSquareIcon className='h-3 w-3' />} width='w-11/12 max-w-5xl'> 35 // here the child 36 <FormEdit data={row} setRefresh={setRefresh} modalTarget={row.customer_uuid} /> 37 </ReuseableModal> 38 </div> 39 ) 40 }, 41 disableSortBy: true 42 } 43 ], 44 [] 45 ); 46 47 return ( 48 <Fragment> 49 <Helmet> 50 <title>Example</title> 51 </Helmet> 52 <section className='p-3'> 53 <div className="bg-base-300 p-3 rounded"> 54 <TablePagination 55 columns={columns} 56 data={data} 57 fetchData={fetchData} 58 loading={loading} 59 pageCount={pageCount} 60 totalRow={totalRow} 61 /> 62 </div> 63 </section> 64 </Fragment> 65 ) 66} 67 68export default PelangganAktif 69}
And here the modal popup
1// file: components/modal/FormEdit.js (child) 2function FormEdit({ data, setRefresh, modalTarget }) { 3 4 const { addToast } = useToast() 5 const initValues = data 6 7 const formSubmit = async (values) => { 8 const updated = await customerUpdate(values) 9 if (updated.type === 'success') { 10 addToast('success', 'top-right', 'Data updated!', `${data.profiles.fullname} detail updated`, 5000) 11 document.getElementById(`modalEdit-${modalTarget}`).click() 12 setRefresh(true) 13 resetForm() 14 } else { 15 addToast('error', 'top-right', 'Data failed to update!', `${data.profiles.fullname} defail failed to update`, 5000) 16 } 17 } 18 19 const { values, errors, touched, handleChange, handleSubmit, resetForm } = useFormik({ 20 initialValues: initValues, 21 onSubmit: formSubmit, 22 enableReinitialize: true 23 }) 24 25 return // your form here 26} 27 28export default FormEdit
That's it!
A demo/repos link
No response