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

时间:2018-04-19 13:19:26

标签: javascript reactjs sorting datatable pagination

我正在制作一个简单的表格,我有分页(单独的组件)和排序。

单击表标题时,表应对更新进行排序。它改变了数据状态。数据已排序但不会更新。当我更改页面(分页组件)并且它具有已排序的数据时,该表将被重新呈现。 问题在于

 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;

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

3 个答案:

答案 0 :(得分:0)

我认为问题可能来自于您尝试在方法this.state中直接更改sortHandler,然后再将其传递给setState

首先尝试克隆this.state.datavar clone = this.state.data.slice(0);

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

将其分配到新状态

此外,您可以避免在方法中多次调用this.setState(),而不是在函数结束时调用一次。

答案 1 :(得分: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.datathis.state.data = this.props.data会在您的上一个案例中犯很多错误。

答案 2 :(得分:0)

The problem is in sortHandler function.

You are sorting the data using javascript sort() method. It is mutating method and doesn't create new object so React.js can't detect that the data has changed.

You should use non-mutating method.

Your code should be

const newData = this.state.data.concat().sort(...); 
this.setState({data: newData});