【问题标题】:Pagination with React from JSON data issue来自 JSON 数据问题的 React 分页
【发布时间】:2017-06-12 01:07:37
【问题描述】:


我陷入了 reactJS 的新手问题(我上周开始学习)。我正在开发一个单页应用程序,它从 Google Book API 呈现搜索结果,一切看起来都很棒,我可以从 api 获取数据(实际上现在我正在使用 AJAX)。

我在过去 8 小时内所做的尝试都无法更新我的 react-paginate 组件中的状态。 可能问题出在我的 handlePageClick 函数中,但是这个模块的文档有点奇怪,加上我对 react 的不熟悉让事情变得更加困难。

这是我的 app.js

import React from 'react';
import ReactDOM from 'react-dom';
import { compose } from 'redux';
import {
  cloneDeep, findIndex, orderBy, keys, values, transforms
} from 'lodash';
import Bookshelf from './bookshelf.js';
import ReactPaginate from 'react-paginate';

import Header from './layout/header.js';
import Footer from './layout/Footer.js';
import Books from './layout/Books.js';
// import {Paginator, paginate } from './helpers';

const app = document.getElementById('app');



export default class Main extends React.Component{
  constructor(props){
    super(props);

    this.state = {
      items:[],
      offset:0
    };

    this.localSubmit = this.localSubmit.bind(this);
    this.onPerPage = this.onPerPage.bind(this);

    this.handlePageClick = this.handlePageClick.bind(this);

  }


  localSubmit(search) {

    this.setState({items: []});
    var component = this;

    $.get("https://www.googleapis.com/books/v1/volumes?q=intitle:" + encodeURIComponent(search) + "&printType=books&orderBy=newest&maxResults=39", function (data) {

      component.setState(data);
      Bookshelf();

      $(".front").css("background", "url(../img/no_book_cover.jpg)");

      for (var i = 0; i < component.state.items.length; i++) {
        if (component.state.items[i].volumeInfo.imageLinks != null) {

          $("#book-" + component.state.items[i].id).find(".front").css("background", "url("+ component.state.items[i].volumeInfo.imageLinks.thumbnail +")");
        }
      }


      $(".front").css("background-size", "100% 100%");
      $(".front").css("border", "2px solid #eee");
      $(".front").css("background-size", "100% 100%");


    });
  }

  handlePageClick(component){
    console.log(component);
    let selected = component.selected;
    let offset = Math.ceil(selected * this.props.perPage);
    console.log("the offset is:"+offset)
    this.setState({offset: offset}, () => {
      // this.localsubmit
    });
  }

  onSelect(page) {
    const pages = Math.ceil(
      this.state.items.length / 9
    );

    console.log(pages);

    this.setState({
      pagination: {
        perPage:this.state.pagination,
        page: Math.min(Math.max(page, 1), pages)
      }
    });
  }
  onPerPage(value) {
    this.setState({
      pagination: {
        page:this.state.pagination,
        perPage: parseInt(value, 10)
      }
    });
  }
  render () {
    const pages = Math.ceil(
      this.state.items.length / 9
    );
    console.log("length:"+this.state.items.length);
    console.log(pages);
    var books = [];
    var content;

    books = this.state.items.map(function(book) {
      return <Books key={book.id} item={book.volumeInfo} identifier={book.id} />;
    });

    if (books.length > 0) {
      content = books;
    } else {
      content = <div className="search-icon" ><span className="glyphicon glyphicon-search"></span></div>
    }

    return (
      <div>
      <Header localSubmit={this.localSubmit}/>
        <div className="main">
                <div id="bookshelf" className="bookshelf">
            {content}
          </div>
          <ReactPaginate previousLabel={"previous"}
               nextLabel={"next"}
               breakLabel={<a href="">...</a>}
               breakClassName={"break-me"}
               pageCount={this.state.pageCount}
               marginPagesDisplayed={2}
               pageRangeDisplayed={5}
               onPageChange={this.handlePageClick}
               containerClassName={"pagination"}
               subContainerClassName={"pages pagination"}
               activeClassName={"active"} />
        </div>
        <Footer />
      </div>
    );

  }

}

ReactDOM.render(<Main  perPage={10}/>, document.getElementById("app"));

这是另一个相关的组件,books

import React from "react";
import ReactDOM from 'react-dom';


var Books = React.createClass({

  getInitialState : function () {
    return ({});
  },
  componentDidMount : function () {

    if (this.props.item != null) {
      this.setState(this.props.item);
    }


  },
  render : function () {

    var authors = "";
    console.log(this.props.item);

    if (this.state.authors != null) {
      for (var i = 0; i < this.state.authors.length; i++) {

        if (i > 1) {
          authors = ", " + this.state.authors[i];
        } else {
          authors = this.state.authors[i];
        }
      }
    }

    var descrip = "...";

    if (this.state.description != null) {
      descrip = this.state.description.substring(0, 180) + "...";
    }

    var id = "";

    if (this.props.identifier != null) {
      id = "book-" + this.props.identifier;
    }

    return (

      <figure>
        <div className="book" id={id}></div>
        <div className="buttons"><a href={this.state.previewLink} target="_blank">Preview</a><a href="#">Details</a></div>
        <figcaption><h2>{this.state.title}<span>{authors}</span></h2></figcaption>
        <div className="details">
          <ul>
            <li>{descrip}</li>
            <li>{this.state.publishedDate}</li>
            <li>{this.state.publisher}</li>
            <li>{this.state.pageCount} pages</li>
          </ul>
        </div>
      </figure>

    );
  }

});

export default Books;

我已经尝试过另一个用于分页的模块,但没有成功,这个看起来更容易,但是缺少一些东西,你们能帮帮我吗?

错误: 当我点击下一页时,我得到了这个Cannot read property 'perPage' of undefined,在page 1 中显示了整个内容,react-paginate 过滤实际上它不起作用。

编辑 2: 我在构造函数中取消了this.handlePageClick = this.handlePageClick.bind(this); 行的注释,但仍然没有过滤器,现在我没有收到任何错误,这让我发疯了 =(

提前致谢!

【问题讨论】:

  • 也许您实际上可以描述引发的错误/异常,或者至少描述预期行为和实际行为,以便我们为您提供帮助:)
  • 绝对是@CharlieBrown,再看一遍 =)

标签: javascript json reactjs pagination


【解决方案1】:

错误:当我单击下一页时,我得到了无法读取未定义的属性“perPage”,并且在第 1 页中显示了整个内容,react-paginate 过滤实际上它不起作用。

您需要在构造函数中将handlePageClick 绑定到this(该行已注释),就像您对onPerPage 和其他方法所做的那样。

更新后编辑 2 好的,现在看起来好多了。但是您的代码确实很混乱,我可以清楚地看到您四处走动,改变事物并尝试。 :) 帮自己一个忙,删除所有的 jQuery 代码,特别是在 Ajax 处理程序中。如果您想要不同的 HTML,只需更新您的组件即可。

要直接回答您的问题,在检查 react-paginate 文档后,它只会为您呈现分页器,但您仍然需要 render 只显示要显示的项目数.在您的代码中,您正在映射完整的 this.state.items 数组,并且每次都会呈现每本书。

除此之外,我看到您在 onPerPageonSelect 方法中创建了新的状态片段,而您没有在 constructor 中初始化。

您的应用需要的唯一状态是:

  1. API 调用返回的items
  2. 当前页面
  3. 可选:页面大小(每页的项目),您在组件外部声明为常量并在需要的任何地方重复使用它,const PAGE_SIZE = 9。您可以稍后将其转换为 prop,以便您的组件的默认页面大小可以从外部配置。

给定前 2 个键,在您的 constructor 中声明您的初始状态,例如:

this.state = {
  items: [],
  currentPage: 1
}

然后,这是重要的部分,将您的 items&lt;Book /&gt; 映射逻辑提取到一个函数,该函数考虑到 PAGE_SIZEcurrentPage 以仅从数组中选择相关项目,例如:

renderBooks(){
  var startIndex = (this.state.currentPage-1)*PAGE_SIZE
  var endIndex = startIndex + PAGE_SIZE

  return this.state.items.slice(startIndex, endIndex).map(item =>
    <Book {...your_props} />
}

最后,在您的渲染方法中,只需在您每次想要渲染书籍时调用 renderBooks() 函数(即每次 this.state.items.length &gt; 0)。

在 Paginate 组件的事件处理程序上,只需为 currentPage 设置适当的值,它就可以解决问题。你不需要所有数学的东西,只要你的分页器中没有 Next 0.25 page 按钮,你就会一直使用整数。 :)

希望对您有所帮助!

P.S:你的 AJAX 处理程序中的 Bookshelf() 调用是什么?你应该只在那里setState({ items })!!并考虑所有组件中 render 方法中的新状态。

【讨论】:

  • 分页现在不会给我任何错误,但仍然不过滤页面。 =(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-13
  • 2020-07-21
  • 2021-07-21
  • 2017-06-02
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
相关资源
最近更新 更多