簡體   English   中英

從 react-js-pagination 獲取分頁器以顯示在頁面上

[英]Getting paginator from react-js-pagination to display on page

我有一個 React 應用程序,它是一個購物網站的前端。

我有一個產品頁面,我試圖將 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);

任何幫助將不勝感激。

謝謝。

好吧,我無法幫助您使用 react-js-pagination,另一方面,我使用 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 first={this.state.first} rows={this.state.rows} totalRecords={yourcomponentlist.length} onPageChange={this.onPageChange}></Paginator>

現在我們來分析一下,我們每頁顯示的行數(rows),以及要顯示的第一行的相對行數(first)。 因此,您可以使用 slice javascript 方法讓您的組件列表與分頁器一起使用,以便在分頁后僅呈現您想要的組件。

<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 是一個很棒的工具帶,它也為您的設計提供了許多主題,我很高興使用它!

好的,所以如果您閱讀我對 Leonel 的回答的評論,您會發現我確實設法讓分頁器從 react-js-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 在產品的最后一頁上不是可點擊的選項。

我還確保向組件添加一個“key”道具,該道具對於顯示該組件的路徑是唯一的。 這是必需的,因為我的分頁依賴於我在聲明“activePage”的組件中設置的狀態,以便當我進入另一種類型的產品頁面(例如從套件產品到坦克產品)時,組件將重新掛載(因為兩條路由都渲染相同的組件,渲染的產品由路由參數決定)並且狀態將恢復到其初始狀態 ({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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM