我有一个反应应用程序,它是购物网站的前端。
我有一个产品页面,我正在尝试将react-js-pagination中的分页添加到其底部,这样我就不必一次呈现整个产品列表。
我已经按照指导从https://www.npmjs.com/package/react-js-pagination实施分页,但我仍然无法显示(页面的其余部分正确显示)。
有人能看出原因吗?
请参阅下面整个页面的代码:
import React from 'react';
import Pagination from 'react-js-pagination';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import changeBrandFilter from '../actions/changeBrandFilter';
import changePriceFilter from '../actions/changePriceFilter';
import CategoryOverview from './CategoryOverview';
import Filter from './Filter';
import ProductsListItem from './ProductsListItem';
import ProductsPageContainerCSS from './ProductsPageContainer.css';
class ProductsPage extends React.Component{
createCategoryOverview() {
return this.props.overview.map(overview => {
return (
<CategoryOverview
title={overview.title}
text={overview.text}
image={overview.imageSource}
alt={overview.imageAlt}
/>
)
})
}
createBrandFilterList() {
return this.props.brandFilters.map(filter => {
return (
<Filter
key={filter.brand}
id={filter.brand}
changeFilter={() => this.props.changeBrandFilter(filter)}
inuse={filter.inuse}
disabled={filter.disabled}
/>
)
})
}
createPriceRangeFilterList() {
return this.props.priceRangeFilters.map(filter => {
return (
<Filter
key={filter.priceRange}
id={filter.priceRange}
changeFilter={() => this.props.changePriceFilter(filter)}
inuse={filter.inuse}
disabled={filter.disabled}
/>
)
})
}
filterDivExtenionToggle () {
var filterDivExtension = document.querySelector('.filterDivExtension');
var chevronUp = document.querySelector('#chevronUp');
var chevronDown = document.querySelector('#chevronDown');
var icon;
if (filterDivExtension.style.display === 'block') {
filterDivExtension.style.display = 'none';
chevronUp.style.display = 'none';
chevronDown.style.display = 'block';
} else {
filterDivExtension.style.display = 'block';
chevronUp.style.display = 'block';
chevronDown.style.display = 'none';
}
}
createProductsList() {
if(this.props.products.length > 0) {
return this.props.products.map(product =>{
if (this.props.products.indexOf(product) >= this.state.activePage -1 && this.props.products.indexOf(product) < (this.state.activePage*12)) {
return (
<ProductsListItem
key={product.id}
brand={product.brand}
model={product.model}
price={product.price}
image={product.image}
link={"/"+this.props.match.params.type+"/"+product.id}
/>
)
}
})} else {
return <div>No products match the filter criteria selected above.</div>
}
}
constructor(props) {
super(props);
this.state = {activePage: 1};
}
handlePageChange(pageNumber) {
this.setState({activePage: pageNumber});
}
render () {
return (
<div>
<div className="container">
{this.createCategoryOverview()}
<div ClassName="row">
<div className= "filterDiv col-12">
<div className="iconCrossbar">
<i id="chevronDown" className="fa fa-chevron-down" onClick={this.filterDivExtenionToggle}></i>
<i id="chevronUp" className="fa fa-chevron-up" onClick={this.filterDivExtenionToggle}></i>
</div>
<div className="filterDivExtension">
<div className="row">
<div className="filtersList col-md-6 col-12">
Filter by Brand:
<div>
{this.createBrandFilterList()}
</div>
</div>
<div className="filtersList col-md-6 col-12">
Filter by Price Range:
<div>
{this.createPriceRangeFilterList()}
</div>
</div>
</div>
</div>
</div>
</div>
<div className="row productsList">
{this.createProductsList()}
</div>
</div>
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={12}
totalItemsCount={this.props.products.length}
pageRangeDisplayed={2}
onChange={this.handlePageChange}
/>
</div>
)
}
};
function mapStateToProps(state , ownProps) {
let brandFilters = state.brandFilters;
let filtered_brandFilters = brandFilters;
filtered_brandFilters = filtered_brandFilters.filter(
filter => filter.type === ownProps.match.params.type
)
let priceRangeFilters = state.priceRangeFilters;
let filtered_priceRangeFilters = priceRangeFilters;
filtered_priceRangeFilters = filtered_priceRangeFilters.filter(
filter => filter.type === ownProps.match.params.type
)
let products = state.products;
let overviews = state.overviews;
let overview = overviews.filter(
overview => overview.type === ownProps.match.params.type
)
let filtered_products = products;
filtered_products = filtered_products.filter(
product => product.type === ownProps.match.params.type //gets type from the the route params and finds products which have type that matches
)
let activeBrandFilters = brandFilters.filter(
item => item.inuse === true
);
activeBrandFilters.forEach(filter => {
filtered_products = filtered_products.filter(
product => product.brand === filter.brand
)
});
let activePriceRangeFilters = priceRangeFilters.filter(
item => item.inuse === true
);
activePriceRangeFilters.forEach(filter => {
filtered_products = filtered_products.filter(
product => product.priceRange === filter.priceRange
);
});
return {
overview: overview,
brandFilters: filtered_brandFilters,
priceRangeFilters: filtered_priceRangeFilters,
products: filtered_products
};
};
function matchDispatchToProps(dispatch){
return bindActionCreators({changeBrandFilter: changeBrandFilter, changePriceFilter: changePriceFilter}, dispatch);
};
export const ProductsPageContainer = connect(mapStateToProps, matchDispatchToProps)(ProductsPage);
非常感谢任何帮助。
感谢。
答案 0 :(得分:1)
好的,如果您阅读我对Leonel的回答的评论,您会发现我确实设法让react-js-paginator的paginator显示但仍然无法使其工作。
我改为制作了自己的自定义基本分页器组件。
请找到我在下面创建的paginator组件:
import React from 'react';
class Paginaton extends React.Component {
render () {
return (
<div className="row">
<div className="pagination">
<button id="prevPage" className="btn" disabled={this.props.disabled1} onClick={() => this.props.onclick1()}>prev</button>
<button id="nextPage" className="btn" disabled={this.props.disabled2} onClick={() => this.props.onclick2()}>next</button>
</div>
</div>
)
}
}
export default Paginaton;
正如您所看到的,这只是一个上一个按钮和一个下一个按钮。
然后,在容器组件中,确保只有需要处于活动状态的按钮显示为活动状态,而不需要处于活动状态的按钮显示为非活动状态。这确保了在产品的第一页上prev不是可点击的选项,而在产品的最后一页上,next不是可点击的选项。
我还确保添加一个&#39;密钥&#39;支持组件显示的路径所独有的组件。这是必要的,因为我的分页依赖于我在组件中设置的状态,该状态声明了“活动页面”。因此,当我继续浏览另一种类型的产品页面时(例如从套件产品到坦克产品),组件将重新安装(因为两个路径都呈现相同的组件,所呈现的产品由路由参数决定)并且状态将恢复到其初始状态({activePage:1})。
请参阅下面的容器组件:
import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import changeBrandFilter from '../actions/changeBrandFilter';
import changePriceFilter from '../actions/changePriceFilter';
import CategoryOverview from './CategoryOverview';
import Filter from './Filter';
import ProductsListItem from './ProductsListItem';
import ProductsPageContainerCSS from './ProductsPageContainer.css';
import Pagination from './Pagination';
class ProductsPage extends React.Component{
createCategoryOverview() {
let i = 1;
return this.props.overview.map(overview => {
i++
return (
<CategoryOverview
key={"catOverview"+i} //each child in an array or iterator should have a unique "key" prop
title={overview.title}
text={overview.text}
image={overview.imageSource}
alt={overview.imageAlt}
/>
)
})
}
createBrandFilterList() {
let i = 1;
return this.props.brandFilters.map(filter => {
i++
return (
<Filter
key={filter.brand+i+"brand"}
name={this.props.match.params.type + "brandFilter"} //so that each seperate group of radio buttons (filters) refer only to each other. (the name is shared within each group)
id={filter.brand}
changeFilterResetPageNumber={() => {this.props.changeBrandFilter(filter); this.handlePageChange(1)}} //without page reset would often get no products displayed on filter application due to the activePage state remaining at the page that was active at the time of filter application
inuse={filter.inuse}
/>
)
})
}
createPriceRangeFilterList() {
let i = 1;
return this.props.priceRangeFilters.map(filter => {
i++
return (
<Filter
key={filter.priceRange+i+"priceRange"}
name={this.props.match.params.type + "priceFilter"}
id={filter.priceRange}
changeFilterResetPageNumber={() => {this.props.changePriceFilter(filter); this.handlePageChange(1)}}
inuse={filter.inuse}
/>
)
})
}
filterDivExtenionToggle () {
var filterDivExtension = document.querySelector('.filterDivExtension');
var chevronUp = document.querySelector('#chevronUp');
var chevronDown = document.querySelector('#chevronDown');
var icon;
if (filterDivExtension.style.display === 'block') {
filterDivExtension.style.display = 'none';
chevronUp.style.display = 'none';
chevronDown.style.display = 'block';
} else {
filterDivExtension.style.display = 'block';
chevronUp.style.display = 'block';
chevronDown.style.display = 'none';
}
}
createProductsList() {
if(this.props.products.length > 0) {
return this.props.products.map(product =>{
if (this.props.products.indexOf(product) >= (this.state.activePage*12) - 12 && this.props.products.indexOf(product) < (this.state.activePage*12)) { //render the 12 (number of products per page) products that correspond to the current (active) page
return (
<ProductsListItem
key={product.id}
brand={product.brand}
model={product.model}
price={product.price}
image={product.image}
link={"/"+this.props.match.params.type+"/"+product.id}
/>
)
}
})} else {
return <div>No products match the filter criteria selected above.</div>
}
}
state = {
activePage: 1
}
handlePageChange(pageNumber) {
this.setState({activePage: pageNumber});
}
createPagination() {
if (this.props.products.length > 12) {
if (this.props.products.length > this.state.activePage * 12 && this.state.activePage > 1) { //if there are products following AND preceding the current page
return (
<Pagination
onclick1={() => this.handlePageChange(this.state.activePage - 1)}
onclick2={() => this.handlePageChange(this.state.activePage + 1)}
disabled1={false}
disabled2={false}
/>
)
} else if (this.props.products.length > this.state.activePage * 12) { //if there are only products following the current page
return (
<Pagination
onclick1={() => this.handlePageChange(this.state.activePage - 1)}
onclick2={() => this.handlePageChange(this.state.activePage + 1)}
disabled1={true}
disabled2={false}
/>
)
} else if (this.state.activePage > 1) { //if there are only products preceding the current page
return (
<Pagination
onclick1={() => this.handlePageChange(this.state.activePage - 1)}
onclick2={() => this.handlePageChange(this.state.activePage + 1)}
disabled1={false}
disabled2={true}
/>
)
}
}
}
render () {
return (
<div>
<div className="container">
{this.createCategoryOverview()}
<div className="row">
<div className= "filterDiv col-12">
<div className="iconCrossbar">
<i id="chevronDown" className="fa fa-chevron-down" onClick={this.filterDivExtenionToggle}></i>
<i id="chevronUp" className="fa fa-chevron-up" onClick={this.filterDivExtenionToggle}></i>
</div>
<div className="filterDivExtension">
<div className="row">
<div className="filtersList col-md-6 col-12">
Filter by Brand:
<div>
{this.createBrandFilterList()}
</div>
</div>
<div className="filtersList col-md-6 col-12">
Filter by Price Range:
<div>
{this.createPriceRangeFilterList()}
</div>
</div>
</div>
</div>
</div>
</div>
<div className="row productsList">
{this.createProductsList()}
</div>
{this.createPagination()}
</div>
</div>
)
}
};
function mapStateToProps(state , ownProps) {
let brandFilters = state.brandFilters;
let filtered_brandFilters = brandFilters;
filtered_brandFilters = filtered_brandFilters.filter(
filter => filter.type === ownProps.match.params.type //gets type from the the route params and finds products which have type that matches
)
let priceRangeFilters = state.priceRangeFilters;
let filtered_priceRangeFilters = priceRangeFilters;
filtered_priceRangeFilters = filtered_priceRangeFilters.filter(
filter => filter.type === ownProps.match.params.type
)
let overviews = state.overviews;
let overview = overviews.filter(
overview => overview.type === ownProps.match.params.type
)
let products = state.products;
let filtered_products = products;
filtered_products = filtered_products.filter(
product => product.type === ownProps.match.params.type
)
let activeBrandFilters = filtered_brandFilters.filter(
item => item.inuse === true
);
activeBrandFilters.forEach(filter => {
if (filter.brand != "ALL") {
filtered_products = filtered_products.filter(
product => product.brand === filter.brand
)
}
});
let activePriceRangeFilters = filtered_priceRangeFilters.filter(
item => item.inuse === true
);
activePriceRangeFilters.forEach(filter => {
if (filter.priceRange != "ALL") {
filtered_products = filtered_products.filter(
product => product.priceRange === filter.priceRange
);
}
});
let key = ownProps.match.params.type;
return {
overview: overview,
brandFilters: filtered_brandFilters,
priceRangeFilters: filtered_priceRangeFilters,
products: filtered_products,
key: key //a change of key property means the component remounts. this was needed so that when on a second page of products (state is activePage: 2) and switching to a 'page' with products type that does not have a second page (uses same components but displays different type of products), no products would be displayed because the component did not remount and thh state remained the same (activePage did not reset to 1)
};
};
function mapDispatchToProps(dispatch){
return bindActionCreators({changeBrandFilter: changeBrandFilter, changePriceFilter: changePriceFilter}, dispatch);
};
export const ProductsPageContainer = connect(mapStateToProps, mapDispatchToProps)(ProductsPage);
答案 1 :(得分:0)
好吧,我无法帮助你使用react-js-pagination,另一方面,我很容易使用react-prime。 Paginator React Prime。好的,我会试着向你解释一下, 首先要了解这个框架给我们带来了什么:
你导入它:
import {Paginator} from 'primereact/components/paginator/Paginator';
然后可能,您将拥有一个必须呈现的组件列表,以便通过它进行分页。 在容器组件上,您必须设置这些值以使您的分页器工作:
constructor() {
super();
this.state = {first: 0, rows: 10};
this.onPageChange = this.onPageChange.bind(this);
}
onPageChange(event) {
this.setState({
first: event.first,
rows: event.rows
});
}
然后你将拥有paginator组件:
<Paginator first={this.state.first} rows={this.state.rows} totalRecords={yourcomponentlist.length} onPageChange={this.onPageChange}></Paginator>
现在让我们分析它,我们在每个页面(行)中显示多个行,以及要显示的第一行的相对数量(第一个)。所以,您可以使用切片javascript方法让您的组件列表与paginator一起使用,以便在分页后仅呈现您希望的组件。
<tbody>
{
this.props.components.slice(this.state.first, this.state.first +
this.state.rows).map((component) => {
return <ComponentListItem key={component._id} {...componentData} />;
})
}
</tbody>
就是这样,我希望我能够帮助你理解这个分页器是如何工作的,react-prime是一个很好的工具带,它有很多主题供你设计,我很高兴使用它!