Что мне нужно сделать, чтобы получить доступ к `currentPage` и `setCurrentPage` внутри моего рендера

avatar
Randy
8 августа 2021 в 17:33
121
1
0

Я пытаюсь следовать этой веб-статье, чтобы реализовать нумерацию страниц.

import React, { useState, useMemo } from "react";
import Config from 'config';
import { formatter } from '../common.js'
import { format } from 'date-fns';
import Pagination from '../Pagination';
import "./Order.css";

let PageSize = 25;

class Portal extends React.Component {
    constructor() {
        super();
        this.state = {
            name: 'React',
            apiData: [],
        };
    }

    async componentDidMount() {        
        console.log('app mounted');

        const tokenString = sessionStorage.getItem("token");
        const token = JSON.parse(tokenString);

        let headers = new Headers({
            "Accept": "application/json",
            "Content-Type": "application/json",
            'Authorization': 'Bearer ' + token.token
        });
        
        const response = await fetch(Config.apiUrl + `/api/Orders/GetAllInvoices`, {
            method: "GET",
            headers: headers
        });
        const json = await response.json();
        console.log(json);
        this.setState({ orderList: json });
    }

    render() {
        const orders = this.state.orderList;
        const [currentPage, setCurrentPage] = useState(1);  <<== Error here

        const currentTableData = useMemo(() => {
            const firstPageIndex = (currentPage - 1) * PageSize;
            const lastPageIndex = firstPageIndex + PageSize;
            return orders.slice(firstPageIndex, lastPageIndex);
        }, [currentPage]);

        return (
            <div>
                <h2>Portal</h2>
                <br />
                <h3>Past Orders</h3>
                <table className="table table-striped table-bordered">
                    <thead>
                        <tr>
                            <th className="number">Invoice Number</th>
                            <th className="date">Invoice Date</th>
                            <th className="amount">Amount</th>
                        </tr>
                    </thead>
                    <tbody>
                        {currentTableData && currentTableData.map(order =>
                            <tr key={order.sopnumbe}>
                                <td>{order.sopnumbe}</td>
                                <td>{format(Date.parse(order.docdate), 'MM/dd/yyyy')}</td>
                                <td>{formatter.format(order.docamnt)}</td>
                            </tr>
                        )}
                    </tbody>
                </table>
                <Pagination
                    className="pagination-bar"
                    currentPage={currentPage}
                    totalCount={orders.length}
                    pageSize={PageSize}
                    onPageChange={page => setCurrentPage(page)}
                />
            </div>
        );
    }
}
export default Portal;

Поскольку это компонент класса, я получаю сообщение об ошибке "Недопустимый вызов ловушки" при попытке useHook внутри компонента класса, как указано здесь.

Я попытался переместить это во внешнюю функцию и вызвать foo() внутри моего рендера:

import React, { useState, useMemo } from "react";
import Config from 'config';
import { formatter } from '../common.js'
import { format } from 'date-fns';
import Pagination from '../Pagination';
import "./Order.css";

let PageSize = 25;

function foo() {
    const [currentPage, setCurrentPage] = useState(1);
}
...

Но теперь, что мне нужно сделать, чтобы получить доступ к currentPage и setCurrentPage внутри моей функции рендеринга, добавить this. или переместить строку const [currentPage, setCurrentPage] = useState(1) в componentDidMount?

Источник
Ala Hamadi
8 августа 2021 в 17:46
0

Компоненты класса не поддерживают хуки. Если вы хотите использовать хуки (useState, useEffect..), вы можете начать с написания нового кода в виде функциональных компонентов с хуками. Вы можете прочитать больше о Hooks-FAQ здесь.

Ответы (1)

avatar
Shubham Khatri
8 августа 2021 в 17:39
1

Крюки предназначены для написания в функциональных компонентах, а не в компонентах класса.

Чтобы написать ту же логику. с компонентами класса вам нужно объявить состояние, как вы уже сделали в конструкторе, и использовать методы жизненного цикла

class Portal extends React.Component {
    constructor() {
        super();
        this.state = {
            name: 'React',
            apiData: [],
            orderList: [],
            currentPage: 1,
            currentTableData: [],
        };
    }

    async componentDidMount() {        
        console.log('app mounted');

        const tokenString = sessionStorage.getItem("token");
        const token = JSON.parse(tokenString);

        let headers = new Headers({
            "Accept": "application/json",
            "Content-Type": "application/json",
            'Authorization': 'Bearer ' + token.token
        });
        
        const response = await fetch(Config.apiUrl + `/api/Orders/GetAllInvoices`, {
            method: "GET",
            headers: headers
        });
        const json = await response.json();
        console.log(json);
        this.setState({ orderList: json });
    }

    componentDidUpdate(_, prevState) {
        if(prevState.currentPage !== this.state.currentPage) {
            const firstPageIndex = (currentPage - 1) * PageSize;
            const lastPageIndex = firstPageIndex + PageSize;
            this.setState({currentTableData: orders.slice(firstPageIndex, lastPageIndex)});
       }
    }
    render() {
        const orders = this.state.orderList;
        const currentTableData = this.state.currentTableData;
        return (
            <div>
                <h2>Portal</h2>
                <br />
                <h3>Past Orders</h3>
                <table className="table table-striped table-bordered">
                    <thead>
                        <tr>
                            <th className="number">Invoice Number</th>
                            <th className="date">Invoice Date</th>
                            <th className="amount">Amount</th>
                        </tr>
                    </thead>
                    <tbody>
                        {currentTableData && currentTableData.map(order =>
                            <tr key={order.sopnumbe}>
                                <td>{order.sopnumbe}</td>
                                <td>{format(Date.parse(order.docdate), 'MM/dd/yyyy')}</td>
                                <td>{formatter.format(order.docamnt)}</td>
                            </tr>
                        )}
                    </tbody>
                </table>
                <Pagination
                    className="pagination-bar"
                    currentPage={currentPage}
                    totalCount={orders.length}
                    pageSize={PageSize}
                    onPageChange={page => this.setState({currentPage: page})}
                />
            </div>
        );
    }
}
export default Portal;
Randy
8 августа 2021 в 18:01
0

Я внес вам изменения, но получаю сообщение об ошибке orders is undefined в строке totalCount={orders.length}.

Shubham Khatri
8 августа 2021 в 18:17
1

инициализировать состояние orderList пустым массивом в конструкторе

Randy
8 августа 2021 в 18:33
0

Теперь я получаю сообщение об ошибке TypeError: paginationRange is undefined в строке 28 Pagination.js. Кстати, спасибо за отличную статью в Интернете.

Shubham Khatri
9 августа 2021 в 05:06
0

@ Рэнди, ты следишь за статьей freeCodeCamp?

Randy
9 августа 2021 в 11:23
0

Да, я. Pagination.js точно такой же.

Shubham Khatri
9 августа 2021 в 11:25
1

Нам придется обрабатывать случай, когда totalCount равен нулю, я думаю, что это отсутствует в статье.

Randy
9 августа 2021 в 12:14
1

Я изменил строку 28 на if (currentPage === 0 || typeof paginationRange === 'undefined' || paginationRange.length < 2). Теперь у меня нет ошибки, но я также не получаю никаких предметов.

Shubham Khatri
9 августа 2021 в 13:10
0

Имеет ли состояние правильное значение для orderList?

Randy
9 августа 2021 в 13:29
0

Да, я изменил строку Portal if (prevState.currentPage !== this.state.currentPage) на if (prevState.currentPage !== this.state.currentPage || prevState.orderList !== this.state.orderList). Теперь он показывает двадцать пять элементов, но строка Pagination не отображается.

Randy
9 августа 2021 в 22:57
0

У меня была опечатка в currentPage={currentPage}. Я исправил и все работает. Спасибо.