how to make InfiniteScroll implementation updated because it update only one time in React table? - javascript

import React, { useEffect, useMemo, useState } from 'react' ;
import { useTable , useSortBy } from 'react-table';
import MOCK_DATA from '../MOCK_DATA.json';
import { Columns } from './columns';
import {Checkbox} from './Checkbox';
import InfiniteScroll from 'react-infinite-scroll-component';
export default function DefaultTable() {
const columns = useMemo(() => Columns , [])
const data = useMemo(() => MOCK_DATA , [])
const [items , setItems] = useState(data);
const [hasMore , setHasMore] = useState(true)
const [offset, setOffset] = useState(10);
const fetchMoreData = () => {
// a fake async api call like which sends
// 20 more records in .5 secs
if (items.length >= items.length +1) {
setHasMore( false );
return;
}
setTimeout(() => {
setOffset( offset + 10);
}, 100);
};
const {getTableProps ,
getTableBodyProps ,
headerGroups ,
rows ,
prepareRow,
allColumns,
getToggleHideAllColumnsProps
} = useTable ({
columns ,
data
},
useSortBy
)
return (
<div>
<div>
<Checkbox {...getToggleHideAllColumnsProps()} /> Toggle All
{
allColumns.map(column =>(
<span key={column.id}>
<label>
<input type='checkbox' {...column.getToggleHiddenProps()} />
{column.Header}
</label>
</span>
))
}
</div>
<div
id="scrollableDiv"
style={{
height: 320,
overflow: 'auto',
display: 'flex',
}}
>
<InfiniteScroll
dataLength={rows.length} //This is important field to render the next data
next={fetchMoreData}
hasMore={hasMore}
style={{ display: 'flex', flexDirection: 'column' }}
loader={<h4>Loading more items...</h4>}
scrollableTarget="scrollableDiv"
endMessage={
<p style={{ textAlign: 'center' }}>
<b>Yay! You have seen it all</b>
</p>
}
>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>{column.render('Header')}
<span>
{column.isSorted
? column.isSortedDesc
? ' 🔽'
: ' 🔼'
: ''}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.slice(0, offset).map((row) => {
// {rows.map((row) => {
prepareRow(row)
return(
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
</InfiniteScroll>
</div>
</div>
)
}

Related

How can I ensure the refresh of a sub component's props?

I have a problem with RTK queries : I have a first component that encapsulates a table. When a refresh occurs - for example when I delete some data - the parent component receives the data and passes it to the child through props but the Table is never updated. So the deleted results still appear on the table.
What is the proper "react/redux" way to generate a refresh of the table ?
Here's some code :
const Results = (props) => {
const router = useRouter()
const { data, error, isError, isLoading, isFetching } = useGetItemsQuery();
if(isLoading) {
return (
<>
<Spinner animation="border" size="sm" role="status" />{' '} Please wait while Loading...
</>
)
}
if(isError) {
return (
<>
<Alert key="warning" variant="warning" style={{marginLeft: "10px"}}>
Warning - There was an error with the request : {error.error}
</Alert>
</>
)
}
const sizePerPageList = [
{
text: '5',
value: 5,
},
];
if (data){
return(
<>
<Card>
<Card.Body>
Traffic results
<TableResults data={data} sizePerPageList={sizePerPageList} />
</Card.Body>
</Card>
</>
)
}
}
export default Results;
And for the second component with the table :
const TableResults = (props) => {
console.log('props - data ', props.data);
const data = React.useMemo(
() => props.data,
[]
)
const columns = React.useMemo(
() => [
{
Header: 'bla bla',
accessor: 'blabla',
}
],
[]
)
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef()
const resolvedRef = ref || defaultRef
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<input type="checkbox" ref={resolvedRef} {...rest} />
</>
)
}
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
page, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
// The rest of these things are super handy, too ;)
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
prepareRow,
state: { pageIndex, pageSize, selectedRowIds },
visibleColumns,
preGlobalFilteredRows,
setGlobalFilter,
selectedFlatRows
} = useTable({ columns, data }, useGlobalFilter, useFilters, useSortBy, usePagination, useRowSelect,
hooks => {
hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllPageRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllPageRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
} )
return (
<>
<DeleteItemButton items={selectedFlatRows} />
<BTable {...getTableProps()} striped bordered hover size="sm">
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td
{...cell.getCellProps()}
style={{
// padding: '10px',
// border: 'solid 1px gray',
// background: 'papayawhip',
}}
>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</BTable>
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</button>{' '}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</button>{' '}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</button>{' '}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</button>{' '}
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</span>
<span>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px' }}
/>
</span>{' '}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value))
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
)
}
export default TableResults;
The DeleteItemButton will generate a simple RTK query that is functioning very well, and that triggers a refresh of the data from the main component :
deleteItems: builder.mutation({
query(data) {
// send array
let sanitized;
sanitized = keywords.filter(item => item);
const data = {
items: sanitized
}
//console.log('data: ', data);
return {
url: `items`,
method: 'DELETE',
body: data
}
},
invalidatesTags: ['Items']
}),
The app is running under nextJS. Any help appreciated !
Thanks
What is the proper "react/redux" way to generate a refresh of the table?
The correct way to refresh your data is by using the providesTags and invalidatesTags features of RTK query, which you are already doing.
The reason that your table is not refreshing is because you explicitly told it to ignore all changes to props.data and to use the initial value for all subsequent renders. This is obviously not what you intended, but it's what you're doing here:
const data = React.useMemo(
() => props.data,
[]
)
A useMemo with an empty dependency array will only execute once. Generally speaking, all variables which you use inside the useMemo should be included as dependencies. So the dependencies array should be [props.data].
Of course this particular useMemo does not do anything and can be safely deleted. It would make sense to have a useMemo if you were doing some reformatting of the props.data variable and wanted to only execute the reformatting when the value of props.data changes.
const data = React.useMemo(
() => someExpensiveComputation(props.data),
[props.data]
);

How to pass Id from child component to the Parent where I called my API

As I am new in react js, in advance I am thankful to all of you.
I am using React table, and I have TablestableRows.js so my button for delete is here but when I call API in this child component it's not working. when I call my API in the parent component AllLeads.js then it's working the API, so now I want to delete one of my elements through an API call. this is the code and API that I am using for this tutorial.
This is the Mapping component that all my data mapping through it:
import {
Table,
Tbody,
Text,
Th,
Thead,
Tr,
useColorModeValue,
} from "#chakra-ui/react";
// Custom components
import Card from "../Card/Card.js";
import CardBody from "../Card/CardBody.js";
import TablesTableRow from "./TablesTableRow";
import React from "react";
const LeadsTable = ({captions, data }) => {
const textColor = useColorModeValue("gray.700", "white");
return (
<Card overflowX={{ sm: "scroll" }} p={6} borderRadius='lg' h={"85vh"}>
<CardBody>
<Table variant='simple' color={textColor} >
<Thead>
<Tr my='.8rem' pl='0px' color='gray.400'>
{captions.map((caption, idx) => {
return (
<Th color='gray.400' key={idx} ps={idx === 0 ? "0px" : null}>
{caption}
</Th>
);
})}
</Tr>
</Thead>
<Tbody>
{data.map((row) => {
return (
<TablesTableRow
key={`${row._id}`}
id={`${row._id}`}
name={row.name}
email={row.email}
phone_no={row.phone_no}
domain={row.domain}
lead_state={row.lead_state}
lead_date={row.lead_date}
graduation_status={row.graduation_status}
// graduation_status
/>
);
})}
</Tbody>
</Table>
</CardBody>
</Card>
);
};
export default LeadsTable;
This is the component that I have CTA Button on it:
import React, { useEffect } from "react";
import {
Badge,
Button,
Flex,
Td,
Text,
Tr,
useColorModeValue,
} from "#chakra-ui/react";
import { Link } from 'react-router-dom';
import { useDispatch } from "react-redux";
import { deleteLeadsAdmin, getLeadsById } from "../../redux/Leads/actionCreator";
const TablesTableRow = (props) => {
const dispatch = useDispatch
const {id, name, email, phone_no, lead_state, lead_date, graduation_status } = props;
const textColor = useColorModeValue("gray.700", "white");
const colorStatus = useColorModeValue("white", "gray.400");
const createdProjectDate = lead_date.split("T", 1);
const onDeleteLead = (e)=>{
e.preventDefault();
console.log(id,'id')
dispatch(deleteLeadsAdmin(id)).then(res=>{
console.log(res,'leads deleted by is')
})
}
return (
<Tr>
<Td pl="0px">
<Flex align="center" py=".8rem" minWidth="100%" flexWrap="nowrap">
<Flex direction="column">
<Text
fontSize="md"
color={textColor}
fontWeight="bold"
minWidth="100%"
>
{name}
</Text>
</Flex>
</Flex>
</Td>
<Td>
<Flex direction="column">
<Text fontSize="sm" color={textColor}
fontWeight="normal">
{email}
</Text>
</Flex>
</Td>
<Td>
<Flex direction="column">
<Text fontSize="sm" color={textColor}
fontWeight="normal">
{phone_no}
</Text>
</Flex>
</Td>
<Td>
<Badge
// bg={status === "Active" ? "green.400" : bgStatus}
bg={lead_state === 0 ? 'pink.500' : lead_state === 1 ? 'green.400' : lead_state === 2 ? 'gray.600' : 'orange.200'}
// color={status === "Active" ? "white" : colorStatus}
color={lead_state === 0 && 1 && 2 ? 'white' : colorStatus}
fontSize="16px"
p="3px 10px"
borderRadius="8px"
>
{lead_state === 0 ? 'Raw Lead' : lead_state === 1 ? 'Converted Leads' : lead_state === 2 ? 'Registerd Leads' : '-'}
</Badge>
</Td>
<Td>
<Flex direction="column">
<Text fontSize="sm" color={textColor}
fontWeight="normal">
{graduation_status}
</Text>
</Flex>
</Td>
{/* graduation_status */}
<Td>
<Flex direction="column">
<Text fontSize="sm" color={textColor}
fontWeight="normal">
{createdProjectDate} // this is the date of each new leads
</Text>
</Flex>
</Td>
<Td>
<Button p="0px" bg="transparent" variant="hover" _hover={{ bg: "#1e91ff", color: "#fff" }} me="10px">
<Link to={`/leads/all-leads/${id}`} >
<Text
fontSize="md"
color={textColor}
fontWeight="bold"
cursor="pointer"
_hover={{ color: "#fff" }}
p={5}
>
Edit
</Text>
</Link>
</Button>
<Button p="0px" bg="transparent" variant="hover" _hover={{ bg: "#f54b4b", color: "#fff" }}
onClick={onDeleteLead}>
<Link to={`/leads/all-leads/${id}`} >
<Text
fontSize="md"
color={textColor}
fontWeight="bold"
cursor="pointer"
_hover={{ color: "#fff" }}
p={5}
>
Delete
</Text>
</Link>
</Button>
</Td>
</Tr>
);
}
export default TablesTableRow;
This is the parent where I call my APIs:
import React, { useState, useEffect } from "react";
import {
Flex,
WrapItem,
Button,
Box,
useColorModeValue,
} from "#chakra-ui/react";
import LeadsTable from "../../component/LeadsTable//LeadsTable";
import { useDispatch } from "react-redux";
import {
deleteLeadsAdmin,
getLeadsForAdmin,
} from "../../redux/Leads/actionCreator";
import HeadTitle from "../../component/HeadTitle/HeadTitle";
import { BodyMain } from "../../component/HeadTitle/BodyMain";
import { useParams } from "react-router";
function AllLeads() {
const dispatch = useDispatch();
const query = useParams();
const [listingLeadsList, setListingLeadsList] = useState([]); // use in listing project list
const [pageLeads, setPageLeads] = useState(5); // use in listing project list
console.log(pageLeads, "page number");
const [id, setID] = useState([]);
console.log(id, "this is the id of leads all leads=");
const chagneNextPage = () => {
setPageLeads(pageLeads + 1);
};
const chagnePreviousPage = () => {
setPageLeads(pageLeads - 1);
};
// console.log(currentPage,' currentPage')
// console.log('this is the leads', listingLeadsList)
const ProjectsForAdmin = () => {
dispatch(getLeadsForAdmin(pageLeads))
.then((res) => {
if (res.success) {
//set data in state to use in listing
setListingLeadsList(res.data.lead);
console.log(res.data.lead._id, "LEADS LIST FRON END");
// setID(res.data.lead[1]._id);
setPageLeads(res.data.next.page);
// setCurrentPage(res.data.next.pag);
} else {
console.log("err Leads", res);
}
})
.catch((err) => console.log("errr leads", err));
};
useEffect(() => {
ProjectsForAdmin();
}, []);
// const onDeleteLead = (e)=>{
// e.preventDefault();
// console.log(id,'id')
// dispatch(deleteLeadsAdmin(id)).then(res=>{
// console.log(res,'leads deleted by is')
// })
// }
const pagesQuantity = 12;
return (
<Flex
flexDirection="column"
h={"100vh"}
px="30px"
bg={useColorModeValue("#f3f2f1", "gray.900")}
>
<HeadTitle title="Leads List" />
<BodyMain>
<WrapItem w={"100%"}>
<Box
bg={useColorModeValue("#fff", "gray.800")}
borderRadius="lg"
w={"100%"}
>
<LeadsTable
padding={20}
title={"Leads Table"}
captions={[
"Name",
"Email",
"Phone",
"Status",
"Graduation Status",
"Date",
"Action",
]}
data={listingLeadsList}
/>
{/* <Button type='submit' onClick={onDeleteLead} me={10}>delete</Button> */}
<Button type="submit" onClick={chagnePreviousPage}>
Previous
</Button>
</Box>
</WrapItem>
</BodyMain>
</Flex>
);
}
export default AllLeads;
Issue resolved: it was about hooks and now I am able to send the id to the API URL useDispatch()
you can try moving you delete function up a level to the parent and passing it to your child table as a prop, then the function will be called at a level above.

getServerSideProps or getStaticProps is not getting called if I use the component as markup in nextjs

I just started with the NextJS. I have created two pages PageA and PageB. Here is the code
PageB
import type { NextPage } from 'next';
import axios from 'axios';
const PageB: NextPage = ({ data = [] }: any) => {
return (
<div>
<table style={{ width: "100%" }}>
<thead>
<tr style={{ width: "100%" }}>
<th style={{ width: "20%" }}>Name</th>
</tr>
</thead>
{/* rows */}
<tbody>
{
data.map((post: any) => {
return <tr key={post._id}>
<td>{post.name}</td>
</tr>;
})
}
</tbody>
</table>
</div>
)
}
export const getServerSideProps = async ({ query }) => {
const myData = await axios.get(`http://localhost:443/api/data`);
return { data: myData.data };
}
export default PageB;
and PageA that will use PageB
import type { NextPage } from 'next';
import axios from 'axios';
import PageB from '../pageb';
const PageA: NextPage = ({ chats }: any) => {
return (
<div>
<table style={{ width: "100%" }}>
<thead>
<tr style={{ width: "100%" }}>
<th style={{ width: "50%" }}>Sender Id</th>
</tr>
</thead>
{/* rows */}
<tbody>
{
chats.map((chat: any) => {
return <tr key={chat._id}>
<td>{chat.sender_id}</td>
</tr>;
})
}
</tbody>
</table>
</div>
<PageB></PageB>
</>
)
}
export const getServerSideProps = async ({ query }) => {
const chats = await axios.get(`http://localhost:443/api/chats`);
// console.log(posts);
return { chats: chats.data };
}
export default PageA;
Now PageB shows the empty list. And if i directly redirect to the /pageb it shows the data.
what is the problem?

React siblings components communication

I have an upload file component, delete file component and files table component(presents the existing files in the system using axios) in the same page:
filesPage.js
import React from 'react';
import UploadFile from '../components/UploadFile'
import DeleteFile from '../components/DeleteFile'
import FilesTable from '../components/FilesTable'
function UploadFiles() {
return (
<div className="filesPage">
<UploadFile/>
<DeleteFile/>
<FilesTable/>
</div>
)
}
export default UploadFiles;
Now I want every time I upload new file or delete one, the files table will be updated which means after the axios post/delete, I need to rerender the files table component and do axios get again to get the active files.
Someone can help?
FilesTable.js
import React, {useState, useEffect} from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TablePagination from '#material-ui/core/TablePagination';
import TableRow from '#material-ui/core/TableRow';
import axios from 'axios';
function FilesTable() {
const [tfaArray, setTfaArray] = useState([]);
useEffect(() => {
axios.get("api/tfa").then((res) => setTfaArray(res.data)).catch((err) => console.log(err));
}, [])
const columns = [
{id: 'fileId', label: '#', minWidth: 100},
{id: 'name', label: 'name', minWidth: 100},
{id: 'date', label: 'upload date', minWidth: 100}
];
const rows = tfaArray.map((tfa, index) => ({fileId: (index + 1), name: tfa.fileName, date: tfa.dateTime.slice(0,24)}) )
const useStyles = makeStyles({
root: {
width: '50%',
position: 'absolute',
right: '10%',
top: '15%',
},
container: {
maxHeight: 322
},
headerCell: {
background: '#F5F5F5',
fontSize: '16px',
zIndex: '0'
}
});
const classes = useStyles();
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(+event.target.value);
setPage(0);
};
return (
<>
<Paper className={classes.root}>
<TableContainer className={classes.container}>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell className={classes.headerCell}
key={column.id}
style={{ minWidth: column.minWidth }}>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row, index) => {
return (
<TableRow hover role="checkbox" tabIndex={-1} key={index}>
{columns.map((column) => {
const value = row[column.id];
return (
<TableCell key={column.id}>
{value}
</TableCell>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 15]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Paper>
</>
)
}
export default FilesTable;
Typically with React you do this by lifting state up as described in this React documentation.
In this case, you'd lift the state to the parent of these components, and have the FilesTable receive the list of files as a prop. (Props are basically component state managed by the parent rather than by the component itself.) Similarly the DeleteFile component would receive the function to call to delete a file, the UploadFile component would receive the function to use to add a file, etc.
Here's a simplified example:
const {useState} = React;
const Parent = () => {
const [files, setFiles] = useState([]);
const addFile = (file) => {
setFiles(files => [...files, file]);
};
const removeFile = (file) => {
setFiles(files => files.filter(f => f !== file));
};
return (
<div>
<FilesTable files={files} removeFile={removeFile} />
<UploadFile addFile={addFile} />
</div>
);
};
const FilesTable = ({files, removeFile}) => {
return (
<React.Fragment>
<div>{files.length === 1 ? "One file:" : `${files.length} files:`}</div>
<ul className="files-table">
{files.map(file => (
<li>
<span>{file}</span>
<span className="remove-file" onClick={() => removeFile(file)}>[X]</span>
</li>
))}
</ul>
</React.Fragment>
);
};
const UploadFile = ({addFile}) => {
const [file, setFile] = useState("");
const onClick = () => {
addFile(file);
setFile("");
};
return (
<div>
<input type="text" value={file} onChange={(e) => setFile(e.target.value)} />
<input type="button" value="Add" disabled={!file} onClick={onClick} />
</div>
);
};
ReactDOM.render(<Parent />, document.getElementById("root"));
ul.files-table {
list-style-type: none;
}
.remove-file {
margin-left: 0.5rem;
cursor: pointer;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

reactjs - React Table Pagination appears to be broken

I am new to using React JS. I have been using react-table to create a component that can filter, sort and paginate some sample data from a JSON file.
Here is the link to the tutorial I have been following:
https://www.freakyjolly.com/react-table-tutorial/#.YBfqqZP7SL4
Here is what I am seeing at the moment, the pagination appears to be broken, I am seeing all of the data appear (1000 rows). I am trying to have around 5-10 records showing at a time.
Here is the App.js code.
import React from 'react';
import logo from './logo.svg';
import './App.css';
import FilterTableComponent from './components/filter.pagination.sorting';
function App() {
return (
<div className="App">
<h3>Filter Table using <code>react-table</code></h3>
<FilterTableComponent />
</div>
);
}
export default App;
Here is the filter.paginate.sorting.js code
import React from "react";
import { useTable, useSortBy, usePagination, useFilters, useGlobalFilter, useAsyncDebounce } from 'react-table';
import 'bootstrap/dist/css/bootstrap.min.css';
import JSONDATA from './MOCK_DATA.json';
// Define a default UI for filtering
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length
const [value, setValue] = React.useState(globalFilter)
const onChange = useAsyncDebounce(value => {
setGlobalFilter(value || undefined)
}, 200)
return (
<span>
Search:{' '}
<input
className="form-control"
value={value || ""}
onChange={e => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`${count} records...`}
/>
</span>
)
}
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length
return (
<input
className="form-control"
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined)
}}
placeholder={`Search ${count} records...`}
/>
)
}
function Table({ columns, data }) {
const defaultColumn = React.useMemo(
() => ({
// Default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
rows,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state,
state: { pageIndex, pageSize },
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
defaultColumn,
initialState: { pageIndex: 0, pageSize: 10 }
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination
)
return (
<div>
<ul className="pagination">
<li className="page-item" onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
<a className="page-link">First</a>
</li>
<li className="page-item" onClick={() => previousPage()} disabled={!canPreviousPage}>
<a className="page-link">{'<'}</a>
</li>
<li className="page-item" onClick={() => nextPage()} disabled={!canNextPage}>
<a className="page-link">{'>'}</a>
</li>
<li className="page-item" onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
<a className="page-link">Last</a>
</li>
<li>
<a className="page-link">
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</a>
</li>
<li>
<a className="page-link">
<input
className="form-control"
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px', height: '20px' }}
/>
</a>
</li>{' '}
<select
className="form-control"
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value))
}}
style={{ width: '120px', height: '38px' }}
>
{[5, 10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</ul>
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
<pre>
<code>
{JSON.stringify(
{
pageIndex,
pageSize,
pageCount,
canNextPage,
canPreviousPage,
},
null,
2
)}
</code>
</pre>
<table className="table" {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render('Header')}
{/* Render the columns filter UI */}
<div>{column.canFilter ? column.render('Filter') : null}</div>
<span>
{column.isSorted
? column.isSortedDesc
? ' '
: ' '
: ''}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<br />
<div>Showing the first 20 results of {rows.length} rows</div>
<div>
<pre>
<code>{JSON.stringify(state.filters, null, 2)}</code>
</pre>
</div>
</div>
)
}
function FilterTableComponent() {
const columns = React.useMemo(
() => [
{
Header: 'Name',
columns: [
{
Header: 'WIP_ID',
accessor: 'WIP_ID',
},
{
Header: 'PRODUCT_SERIAL_NUMBER',
accessor: 'PRODUCT_SERIAL_NUMBER'
},
],
},
{
Header: 'Info',
columns: [
{
Header: 'DATE',
accessor: 'DATE'
},
{
Header: 'BUCKET_NAME',
accessor: 'BUCKET_NAME'
},
{
Header: 'CREATED_TS',
accessor: 'CREATED_TS'
},
{
Header: 'FILE_NAME',
accessor: 'FILE_NAME'
},
],
},
],
[]
)
const data = JSONDATA
return (
<Table columns={columns} data={data} />
)
}
export default FilterTableComponent;
Here is a sample of what the JSON file looks like. Named - MOCK_DATA.json
[{"WIP_ID":"56c97f3e-1c3f-4463-beb2-1af58ebe0db0","PRODUCT_SERIAL_NUMBER":"eab8304c-43e2-4f70-a23a-2db75bf2ce50","DATE":"29/06/2020","BUCKET_NAME":"Bytecard","CREATED_TS":"03/10/2020","FILE_NAME":"elit_proin.tiff"},
{"WIP_ID":"b358a03b-fee6-4957-9017-1de3d9846264","PRODUCT_SERIAL_NUMBER":"b974e89e-9bf9-4329-bc13-1afc3bdd52e0","DATE":"20/12/2020","BUCKET_NAME":"Vagram","CREATED_TS":"25/11/2020","FILE_NAME":"condimentum_id_luctus.mov"},
{"WIP_ID":"9fab6d70-72bc-40ae-a99f-5ae31dc47aec","PRODUCT_SERIAL_NUMBER":"8f9f70ce-b940-486b-a003-5c9db031e54e","DATE":"15/02/2020","BUCKET_NAME":"Domainer","CREATED_TS":"06/05/2020","FILE_NAME":"interdum_in_ante.tiff"},
{"WIP_ID":"5bb40cfb-99dc-413a-8b5f-0b6612e45d34","PRODUCT_SERIAL_NUMBER":"3bab0d2b-5464-4c5d-b1c8-0ba6b32e60fa","DATE":"14/03/2020","BUCKET_NAME":"Lotlux","CREATED_TS":"11/05/2020","FILE_NAME":"diam_nam_tristique.avi"},
{"WIP_ID":"95ae9754-e288-4ceb-b7cf-1b27892e7ace","PRODUCT_SERIAL_NUMBER":"1280dfb1-152d-44fd-aed7-4de8b8b573a6","DATE":"04/04/2020","BUCKET_NAME":"Gembucket","CREATED_TS":"14/10/2020","FILE_NAME":"vehicula.pdf"},
I think you need to change this in your tbody
{rows.map((row,i) =>
to
{page.map((row,i) =>

Categories