带有排序和分页功能的 React 表格不会更新

问题描述 投票:0回答:3

我正在 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)}>&lt; 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 &gt;</a>
            </li>
        </ul>
    );
}
}

Pagination.propTypes = propTypes;
Pagination.defaultProps
export default Pagination;

编辑:分页的一部分已移至表格组件,现在可以正常工作

javascript reactjs sorting datatable pagination
3个回答
0
投票

我认为问题可能来自于您尝试直接在方法

this.state
中更改
sortHandler
,然后再将其传递给
setState

首先尝试克隆

this.state.data
var clone = this.state.data.slice(0);

然后操纵 (

sort
) 它,最后使用
this.setState({ data: clone })

将其分配给您的新状态

此外,您可以避免在方法中多次调用

this.setState()
,而不是在函数结束时调用一次。


0
投票

我在这里发现了几个问题。

第一:不要通过

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
会在你的最后一个案例中犯很多错误。


0
投票

问题出在

sortHandler
函数上。

您正在使用 javascript

sort()
方法对数据进行排序。它是变异方法并且不会创建新对象,因此 React.js 无法检测到数据已更改。

你应该使用非变异方法。

您的代码应该是

const newData = this.state.data.concat().sort(...); 
this.setState({data: newData});
© www.soinside.com 2019 - 2024. All rights reserved.