Я новичок в реагирующей таблице. Я пытаюсь реализовать разбивку на страницы на стороне сервера, но не понимаю, как обнаружить изменение страницы в новой версии таблицы реагирования. Я использую правильные данные для выборки. Я не могу обнаружить изменение. Каждый раз, когда я нажимаю кнопку «Далее», я должен иметь возможность изменять значение смещения в конечной точке API с шагом 20 для получения новых данных. Я не могу выполнить эту операцию. Пожалуйста, помогите.
import React, { useEffect, useState, useMemo } from 'react'
import { URLs } from "../../../Config/url";
import cookie from 'react-cookies';
import "./OrderManagementScreen.css"
import { useTable, usePagination, useSortBy } from 'react-table';
import styled from 'styled-components';
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid lightgray;
width: 100%;
text-align: "center" !important;
tr {
:last-child {
td {
border-bottom: 0;
text-align: "center" !important;
}
}
}
th {
padding: 3px;
box-shadow: 0px 5px 7px 2px lightgrey;
}
td {
padding: 5px;
}
th,
td {
margin: 0;
text-align: "center";
border-bottom: 1px solid #73737361;
border-right: 1px solid #73737361;
:last-child {
border-right: 0;
}
}
}
.pagination {
}
`;
const WrapperTable = styled.div`
background: #ffffff;
box-shadow: 3px 3px 2px 0px rgb(162 161 161 / 75%) !important;
border-radius: 5px;
`
const Table = ({ columns, data }) => {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
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,
state: { pageIndex, pageSize, sortBy },
} = useTable(
{
columns,
data,
initialState: { pageIndex: 0 },
},
useSortBy,
usePagination
);
// const sorted = column.isSorted ? (column.isSortedDesc ? " 🔽" : " 🔼") : "";
// const sorted = column.isSorted ? (column.isSortedDesc ? {borderTop:"1px solid "} :{borderTop:"1px solid "}) : "";
// Render the UI for your table
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render("Header")}
{/* Add a sort direction indicator */}
<span>
{column.isSorted
? column.isSortedDesc
? " 🔽"
: " 🔼"
: ""}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render("Cell")}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
{/*
Pagination can be built however you'd like.
This is just a very basic UI implementation:
*/}
<div className = "pagination">
{/* <button
className = "pagination-btn"
onClick = {() => gotoPage(0)}
disabled = {!canPreviousPage}
>
First
</button> */}
<button
className = "pagination-btn"
onClick = {() => previousPage()}
disabled = {!canPreviousPage}
>
Previous
</button>
<span className = "pagination-btn text-center">
Page{" "}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{" "}
</span>
<button
className = "pagination-btn"
onClick = {() => nextPage()}
disabled = {!canNextPage}
>
Next
</button>
{/* <button
className = "pagination-btn"
onClick = {() => gotoPage(pageCount - 1)}
disabled = {!canNextPage}
>
Last
</button> */}
{/* <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>
</>
);
};
const OrderManagementScreen = () => {
const token = cookie.load("userObj").data.token;
//orderid, outletname, area, distributor, ordervalue, outlet type, discount group, salesofficer,order
const [tableData, SetData] = useState([]);
const [loading, setLoading] = React.useState(false);
const fetchIdRef = React.useRef(0);
const sortIdRef = React.useRef(0);
const columns = React.useMemo(
() => [
{
Header: "Order Id",
accessor: "id",
},
{
Header: "Outlet Name",
id: "outlet_detail",
accessor: data => {
let output = [];
data.outlet_detail.map(item => {
return output.push(item.name);
});
return output.join(', ');
}
},
{
Header: "Area",
id: "area",
accessor: data => {
let output = [];
data.outlet_detail.map(item => {
return output.push(item.area__name);
});
return output.join(', ');
}
},
{
Header: "Distributor",
id: "distributor",
accessor: data => {
let output = [];
data.outlet_detail.map(item => {
return output.push(item.distributor_name);
});
return output.join(', ');
}
},
{
Header: "Order Value",
accessor: "total_price",
},
{
Header: "Outlet Type",
id: "outlet_type__name",
accessor: data => {
let output = [];
data.outlet_detail.map(item => {
return output.push(item.final_value);
});
return output.join(', ');
}
},
{
Header: "Discount Group",
id: "discount__name",
accessor: data => {
let output = [];
data.outlet_detail.map(item => {
return output.push(item.discount__name);
});
return output.join(', ');
}
},
{
Header: "Sales Officer",
id: "sales_officer",
accessor: data => {
let output = [];
data.outlet_detail.map(item => {
return output.push(item.by_user__username);
});
return output.join(', ');
}
}
],
[]
);
const listdata = async () => {
const response = await fetch(`${URLs.orderUrl}?limit=20&offset=0`, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${token}`
}
})
const data = await response.json();
SetData(data);
}
const fetchData = React.useCallback(({ pageSize, pageIndex, sortBy }) => {
// This will get called when the table needs new data
// You could fetch your data from literally anywhere,
// even a server. But for this example, we'll just fake it.
// Give this fetch an ID
console.info(pageIndex);
console.info(pageSize);
const fetchId = ++fetchIdRef.current;
// Set the loading state
setLoading(true);
// We'll even set a delay to simulate a server here
setTimeout(() => {
// Only update the data if this is the latest fetch
if (fetchId === fetchIdRef.current) {
const startRow = pageSize * pageIndex;
const endRow = startRow + pageSize;
if (sortBy.length === 0) {
SetData(tableData.sort().slice(startRow, endRow));
} else {
SetData(
tableData
.sort((a, b) => {
const field = sortBy[0].id;
const desc = sortBy[0].desc;
if (a[field] < b[field]) {
return desc ? -1 : 1;
}
if (a[field] > b[field]) {
return desc ? 1 : -1;
}
return 0;
})
.slice(startRow, endRow)
);
}
// Your server could send back total page count.
// For now we'll just fake it, too
// setPageCount(Math.ceil(serverData.length / pageSize));
setLoading(false);
}
}, 1000);
}, []);
useEffect(() => {
listdata();
}, [])
return (
<div className = "p-3 text-center">
<h4>Order Management</h4>
<WrapperTable>
<Styles>
<Table columns = {columns} fetchData = {fetchData} data = {tableData} />
</Styles>
</WrapperTable>
</div>
)
}
export default OrderManagementScreen;
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Во-первых, вам нужно понять основную разницу между нумерацией страниц на стороне клиента и на стороне сервера.
В пагинации на стороне клиента у нас уже есть все данные для всех страниц, которые нам нужно отобразить в таблице, а это значит, что мы также знаем общее количество (totalcount=pagesize*number of pages
).
Теперь сравните это с разбиением на страницы на стороне сервера. Мы получим фрагмент данных, который мы запрашиваем, что означает, что мы сохраняем размер страницы равным 10 и у нас есть 100 данных на нашем сервере, но поскольку мы запросили 10, мы получим только 10 элементов. Тогда как компонент пагинации узнает, какое общее количество страниц ему нужно отобразить?
Вот почему нам также нужен общий счет с сервера, когда мы извлекаем данные.
Но подождите, нам это нужно каждый раз? Ну, это зависит от вашего варианта использования. В общем, нам нужно общее количество либо в первый раз, либо в случае, если мы делаем какой-либо поиск или фильтрацию.
Теперь перейдем к вашему решению-
В таблице реагирования, если мы явно не установили флаг manualPagination
как true
, тогда он будет обрабатывать количество страниц на основе предоставленных вами данных и размера страницы, поэтому он автоматически обработает разбиение на страницы. Итак, нам нужно сделать это manualPagination
, поскольку true
в options
мы передали useTable
, а также нам нужно указать общее количество страниц, которое равно pageCount
. Так что это будет что-то вроде
useTable(
{
columns,
data,
initialState: { pageIndex: 0 },
},
useSortBy,
usePagination,
manualPagination: true,
pageCount: (totalcount/pagesize),//you can handle this calculation in your fetchdata method
);
а затем добавьте вызов выборки данных внутри нового useEffect с вашим индексом страницы и размер страницы как зависимости
React.useEffect(() => {
fetchData({ pageIndex, pageSize })
}, [fetchData, pageIndex, pageSize])
Я надеюсь, что это решит вашу проблему. Это также хорошо объяснено в документации реагирующей таблицы с подходящим кодшеринговым примером. Загляните сюда