我正在 React 中制作一个简单的表格,其中有分页(单独的组件)和排序。
单击表头时,表应该对更新进行排序。它改变数据的状态。数据已排序但未更新。当我更改页面(分页组件)时,该表会重新呈现,并且它确实具有排序的数据。 问题出在
this.state.pageOfItems.map((element, index) =>
如果我将其更改为
this.state.data.map((element, index) =>
然后排序可以工作,但分页不行
请帮助我在单击表头时立即更新表数据。
表格组件:
import React, { Component } from 'react';
import classes from './Table.css';
import data from 'data.json';
import Pagination from '../Pagination/Pagination';
class Table extends Component {
constructor(props){
super(props);
this.state = {
data: props.data,
headings: Object.keys(props.data[0]),
sortOrder: props.sortOrder || "original",
sortKey: props.sortKey || null,
pageOfItems: []
};
this.sortHandler = this.sortHandler.bind(this);
this.onChangePage = this.onChangePage.bind(this);
}
componentWillMount() {
//TODO: only apply this to the root element of the table component
document.addEventListener('dragover', (event) => {
event.preventDefault();
});
}
sortHandler(e){
const sortKey = e.target.dataset.sortcolumn;
const currentSortKey = this.state.sortKey;
const currentSortOrder = (sortKey === currentSortKey) ? this.state.sortOrder : "original";
this.setState({sortKey: e.target.dataset.sortcolumn});
console.log(currentSortOrder)
switch(currentSortOrder){
case "original":
this.setState({sortOrder: "ascending"});
this.state.data.sort((a, b)=>{
if (a[sortKey] < b[sortKey]) {
return -1;
}
if (a[sortKey] > b[sortKey]) {
return 1;
}
return 0;
});
break;
case "ascending":
this.setState({sortOrder: "descending"});
this.state.data.sort((a, b)=>{
if (a[sortKey] < b[sortKey]) {
return 1;
}
if (a[sortKey] > b[sortKey]) {
return -1;
}
return 0;
});
break;
case "descending":
this.setState({sortOrder: "original"});
this.state.data = this.props.data;
break;
}
this.setState({data: this.state.data});
console.log(this.state.data);
}
onChangePage(pageOfItems) {
// update state with new page of items
this.setState({ pageOfItems: pageOfItems });
}
render() {
return (
<div role="region" aria-labelledby={this.props.id} tabindex="0" style={{overflow: 'auto'}}>
<table cellSpacing="0" cellPadding="0" data-sortorder={this.state.sortOrder}>
{this.props.caption &&
<caption id={this.props.id}>{this.props.caption}</caption>
}
<thead>
<tr>
{this.state.headings.map((element, index) => {
return (
<th
data-sortcolumn={element}
id={'header' + index}
onClick={this.sortHandler}>
{element}
</th>
)
})}
</tr>
</thead>
<tbody>
{this.state.pageOfItems.map((element, index) => {
return (
<tr
id={'row' + index}>
{element && Object.values(element).map((cell)=>{
return <td>
{cell}
</td>
})}
</tr>
)
})}
</tbody>
</table>
<Pagination items={this.state.data} onChangePage={this.onChangePage} />
</div>
);
}
}
分页组件:
import React from 'react';
import PropTypes from 'prop-types';
const propTypes = {
items: PropTypes.array.isRequired,
onChangePage: PropTypes.func.isRequired,
initialPage: PropTypes.number
}
const defaultProps = {
initialPage: 1
}
class Pagination extends React.Component {
constructor(props) {
super(props);
this.state = { pager: {} };
}
componentWillMount() {
this.setPage(this.props.initialPage);
}
setPage(page) {
var items = this.props.items;
var pager = this.state.pager;
if (page < 1 || page > pager.totalPages) {
return;
}
// get new pager object for specified page
pager = this.getPager(items.length, page);
// get new page of items from items array
var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
// update state
this.setState({ pager: pager });
// call change page function in parent component
this.props.onChangePage(pageOfItems);
}
getPager(totalItems, currentPage, pageSize) {
// default to first page
currentPage = currentPage || 1;
// default page size is 10
pageSize = pageSize || 5;
// calculate total pages
var totalPages = Math.ceil(totalItems / pageSize);
var startPage, endPage;
if (totalPages <= 10) {
// less than 10 total pages so show all
startPage = 1;
endPage = totalPages;
} else {
// more than 10 total pages so calculate start and end pages
if (currentPage <= 6) {
startPage = 1;
endPage = 10;
} else if (currentPage + 4 >= totalPages) {
startPage = totalPages - 9;
endPage = totalPages;
} else {
startPage = currentPage - 5;
endPage = currentPage + 4;
}
}
// calculate start and end item indexes
var startIndex = (currentPage - 1) * pageSize;
var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
// create an array of pages to ng-repeat in the pager control
var pages = [...Array((endPage + 1) - startPage).keys()].map(i => startPage + i);
// return object with all pager properties required by the view
return {
totalItems: totalItems,
currentPage: currentPage,
pageSize: pageSize,
totalPages: totalPages,
startPage: startPage,
endPage: endPage,
startIndex: startIndex,
endIndex: endIndex,
pages: pages
};
}
render() {
var pager = this.state.pager;
return (
<ul className="pagination">
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.currentPage - 1)}>< back</a>
</li>
{pager.pages.map((page, index) =>
<li key={index} className={pager.currentPage === page ? 'active' : ''}>
<a onClick={() => this.setPage(page)}>{page}</a>
</li>
)}
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.currentPage + 1)}>next ></a>
</li>
</ul>
);
}
}
Pagination.propTypes = propTypes;
Pagination.defaultProps
export default Pagination;
编辑:分页的一部分已移至表格组件,现在可以正常工作
我认为问题可能来自于您尝试直接在方法
this.state
中更改sortHandler
,然后再将其传递给setState
。
首先尝试克隆
this.state.data
:var clone = this.state.data.slice(0);
然后操纵 (
sort
) 它,最后使用 this.setState({ data: clone })
将其分配给您的新状态
此外,您可以避免在方法中多次调用
this.setState()
,而不是在函数结束时调用一次。
我在这里发现了几个问题。
第一:不要通过
this.state['arg']=
分配状态。这是一个不好的做法。请使用 this.setState()
来代替。
第二:
this.setState()
它是异步函数,别忘了。使用回调。 this.setState({ data }, () => anotherFunction())
在您的情况下,您可以使用 lodash
cloneDeep()
方法。它返回对象的深层副本,因此您不会更改原始对象。 const data = _.cloneDeep(this.state.data).sort()
。
所以。
this.setState({ sortKey: e.target.dataset.sortcolumn }, () => putYourSwitchHere());
之后,
this.setState({sortOrder: "ascending"});
this.state.data.sort((a, b)=>{
if (a[sortKey] < b[sortKey]) {
return -1;
}
if (a[sortKey] > b[sortKey]) {
return 1;
}
return 0;
});
break;
尝试使用:
const data = _.cloneDeep(this.state.data).sort((a, b)=>{
if (a[sortKey] < b[sortKey]) {
return -1;
}
if (a[sortKey] > b[sortKey]) {
return 1;
}
return 0;
});
this.setState({sortOrder: "ascending", data});
break;
你已经分配了
this.state.data
,this.state.data = this.props.data
会在你的最后一个案例中犯很多错误。
问题出在
sortHandler
函数上。
您正在使用 javascript
sort()
方法对数据进行排序。它是变异方法并且不会创建新对象,因此 React.js 无法检测到数据已更改。
你应该使用非变异方法。
您的代码应该是
const newData = this.state.data.concat().sort(...);
this.setState({data: newData});