数据在分页组件中页面更改后没有正确更新。

huangapple go评论71阅读模式
英文:

Data is not updated correctly after page changes in Pagination Component

问题

以下是代码的翻译:

分页组件:

import React from 'react';
import classnames from 'classnames';
import { usePagination, DOTS } from './usePagination';
import './pagination.css';

const Pagination = props => {
  const {
    onPageChange,
    totalCount,
    siblingCount = 1,
    currentPage,
    pageSize,
    className
  } = props;

  const paginationRange = usePagination({
    currentPage,
    totalCount,
    siblingCount,
    pageSize
  });

  if (currentPage === 0 || paginationRange.length < 2) {
    return null;
  }

  const onNext = () => {
    onPageChange(currentPage + 1);
  };

  const onPrevious = () => {
    onPageChange(currentPage - 1);
  };

  let lastPage = paginationRange[paginationRange.length - 1];
  return (
    <ul
      className={classnames('pagination-container', { [className]: className })}
    >
      <li
        className={classnames('pagination-item', {
          disabled: currentPage === 1
        })}
        onClick={onPrevious}
      >
        <div className="arrow left" />
      </li>
      {paginationRange.map(pageNumber => {
        if (pageNumber === DOTS) {
          return <li className="pagination-item dots">...</li>;
        }

        return (
          <li
            className={classnames('pagination-item', {
              selected: pageNumber === currentPage
            })}
            onClick={() => onPageChange(pageNumber)}
          >
            {pageNumber}
          </li>
        );
      })}
      <li
        className={classnames('pagination-item', {
          disabled: currentPage === lastPage
        })}
        onClick={onNext}
      >
        <div className="arrow right" />
      </li>
    </ul>
  );
};

export default Pagination;

评论页面中的代码:

import React, { useEffect, useState, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import LoadingSpinner from "../Commons/LoadingSpinner";
import FeedCheckFilter from "../Commons/Filters/Filter";
import { getLimitedReviews, updateFilters } from '../../services/FiltersService';
import Review from './Review';
import Pagination from "../Commons/Pagination/Pagination";

let PageSize = 10;

const initialState = {
    limit: 10,
    offset: 0,
    reviews: [],
    count: 0
}

export default function Reviews() {
    const dispatch = useDispatch()
    const token = useSelector((state) => state.user.profile.token) 
    const username = useSelector((state) => state.user.profile.auth)
    const reviews = useSelector((state) => state.reviewsData.reviews) 
    const [currentPage, setCurrentPage] = useState(1);
    const [reviewsState, setReviewsState] = useState(initialState)
    // ...
    
    const loadData = async (queryUrl = filters.url, limit=10, offset=0) => {
        setIsLoading(true)
        // let queryUrl = filters.url;
        if (limit || offset) {
            let action = await getLimitedReviews(token, username, queryUrl || defaultQueryUrl, limit, offset)
            setReviewsState(action.payload)
            dispatch(action)
        }
        setIsLoading(false)
    }

    const currentReviewsData = useMemo(() => {
        const firstPageIndex = (currentPage - 1) * PageSize;
        const lastPageIndex = firstPageIndex + PageSize;
        loadData(filters.url, lastPageIndex, firstPageIndex)
        if (reviews) {
            return reviews
        } else {
            return []
        }
    }, [currentPage]);

    // ...
    
    useEffect(() => {
        loadData();
    }, [])
   
    // ...

    return (
        <div>
            <h1>Reviews</h1>
            {isLoading ? <LoadingSpinner /> : 
                <>
                    // ...
                    {currentReviewsData.map(item => {
                        return (<Review key={item.id} review={item} />)
                    })

                    <Pagination
                        className="pagination-bar"
                        currentPage={currentPage}
                        totalCount={reviewsState.count}
                        pageSize={PageSize}
                        onPageChange={page => setCurrentPage(page)}
                    />
                </>
            }
        </div>
    )
}

用于分页的钩子函数:

import React from 'react';
import { useMemo } from 'react';

export const DOTS = '...';

const range = (start, end) => {
  let length = end - start + 1;
  return Array.from({ length }, (_, idx) => idx + start);
};

export const usePagination = ({
  totalCount,
  pageSize,
  siblingCount = 1,
  currentPage
}) => {
  const paginationRange = useMemo(() => {
    const totalPageCount = Math.ceil(totalCount / pageSize);

    // Pages count is determined as siblingCount + firstPage + lastPage + currentPage + 2*DOTS
    const totalPageNumbers = siblingCount + 5;

    /*
      If the number of pages is less than the page numbers we want to show in our
      paginationComponent, we return the range [1..totalPageCount]
    */
    if (totalPageNumbers >= totalPageCount) {
      return range(1, totalPageCount);
    }

    const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
    const rightSiblingIndex = Math.min(
      currentPage + siblingCount,
      totalPageCount
    );

    /*
      We do not want to show dots if there is only one position left 
      after/before the left/right page count as that would lead to a change if our Pagination
      component size which we do not want
    */
    const shouldShowLeftDots = leftSiblingIndex > 2;
    const shouldShowRightDots = rightSiblingIndex < totalPageCount - 2;

    const firstPageIndex = 1;
    const lastPageIndex = totalPageCount;

    if (!shouldShowLeftDots && shouldShowRightDots) {
      let leftItemCount = 3 + 2 * siblingCount;
      let leftRange = range(1, leftItemCount);

      return [...leftRange, DOTS, totalPageCount];
    }

    if (shouldShowLeftDots && !shouldShowRightDots) {
      let rightItemCount = 3 + 2 * siblingCount;
      let rightRange = range(
        totalPageCount - rightItemCount + 1,
        totalPageCount
      );
      return [firstPageIndex, DOTS, ...rightRange];
    }

    if (shouldShowLeftDots && shouldShowRightDots) {
      let middleRange = range(leftSiblingIndex, rightSiblingIndex);
      return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];
    }
  }, [totalCount, pageSize, siblingCount, currentPage]);

  return paginationRange;
};

以上是你提供的代码的翻译部分,不包含其他内容。

英文:

Here I have the pagination component:

import React from &#39;react&#39;;
import classnames from &#39;classnames&#39;;
import { usePagination, DOTS } from &#39;./usePagination&#39;;
import &#39;./pagination.css&#39;;
const Pagination = props =&gt; {
const {
onPageChange,
totalCount,
siblingCount = 1,
currentPage,
pageSize,
className
} = props;
const paginationRange = usePagination({
currentPage,
totalCount,
siblingCount,
pageSize
});
if (currentPage === 0 || paginationRange.length &lt; 2) {
return null;
}
const onNext = () =&gt; {
onPageChange(currentPage + 1);
};
const onPrevious = () =&gt; {
onPageChange(currentPage - 1);
};
let lastPage = paginationRange[paginationRange.length - 1];
return (
&lt;ul
className={classnames(&#39;pagination-container&#39;, { [className]: className })}
&gt;
&lt;li
className={classnames(&#39;pagination-item&#39;, {
disabled: currentPage === 1
})}
onClick={onPrevious}
&gt;
&lt;div className=&quot;arrow left&quot; /&gt;
&lt;/li&gt;
{paginationRange.map(pageNumber =&gt; {
if (pageNumber === DOTS) {
return &lt;li className=&quot;pagination-item dots&quot;&gt;&amp;#8230;&lt;/li&gt;;
}
return (
&lt;li
className={classnames(&#39;pagination-item&#39;, {
selected: pageNumber === currentPage
})}
onClick={() =&gt; onPageChange(pageNumber)}
&gt;
{pageNumber}
&lt;/li&gt;
);
})}
&lt;li
className={classnames(&#39;pagination-item&#39;, {
disabled: currentPage === lastPage
})}
onClick={onNext}
&gt;
&lt;div className=&quot;arrow right&quot; /&gt;
&lt;/li&gt;
&lt;/ul&gt;
);
};
export default Pagination;

And it is integrated in review's page like that:

import React, { useEffect, useState, useMemo } from &quot;react&quot;;
import { useDispatch, useSelector } from &quot;react-redux&quot;;
import LoadingSpinner from &quot;../Commons/LoadingSpinner&quot;;
import FeedCheckFilter from &quot;../Commons/Filters/Filter&quot;;
import { getLimitedReviews, updateFilters } from &#39;../../services/FiltersService&#39;;
import Review from &#39;./Review&#39;;
import Pagination from &quot;../Commons/Pagination/Pagination&quot;;
let PageSize = 10;
const initialState = {
limit: 10,
offset: 0,
reviews: [],
count: 0
}
export default function Reviews() {
const dispatch = useDispatch()
const token = useSelector((state) =&gt; state.user.profile.token) 
const username = useSelector((state) =&gt; state.user.profile.auth)
const reviews = useSelector((state) =&gt; state.reviewsData.reviews) 
const [currentPage, setCurrentPage] = useState(1);
const [reviewsState, setReviewsState] = useState(initialState)
...
const loadData = async (queryUrl = filters.url, limit=10, offset=0) =&gt; {
setIsLoading(true)
// let queryUrl = filters.url;
if (limit || offset) {
let action = await getLimitedReviews(token, username, queryUrl || defaultQueryUrl, limit, offset)
setReviewsState(action.payload)
dispatch(action)
}
setIsLoading(false)
}
const currentReviewsData = useMemo(() =&gt; {
const firstPageIndex = (currentPage - 1) * PageSize;
const lastPageIndex = firstPageIndex + PageSize;
loadData(filters.url, lastPageIndex, firstPageIndex)
if (reviews) {
return reviews
} else {
return []
}
}, [currentPage]);
...
useEffect(() =&gt; {
loadData();
}, [])
...
return (
&lt;div&gt;
&lt;h1&gt;Reviews&lt;/h1&gt;
{isLoading ? &lt;LoadingSpinner /&gt; : 
&lt;&gt;
...
{currentReviewsData.map(item =&gt; {
return (&lt;Review key={item.id} review={item} /&gt;)
})}
&lt;Pagination
className=&quot;pagination-bar&quot;
currentPage={currentPage}
totalCount={reviewsState.count}
pageSize={PageSize}
onPageChange={page =&gt; setCurrentPage(page)}
/&gt;
&lt;/&gt;
}
&lt;/div&gt;
)
}

The problem is that when I press the button to go from page 1 to page 2, the reviews are updated only after render. So the page remains with the reviews from the previous page.
For example if I am in the 5th page, i press the button to go on the 6th. Here on the 6th page I see the reviews from 5th and now if I go to page 7 for example, then I will see the reviews from page 6.

Here I have a hook that I'm using for pagination but I think the problem is not from here:

import React from &#39;react&#39;;
import { useMemo } from &#39;react&#39;;
export const DOTS = &#39;...&#39;;
const range = (start, end) =&gt; {
let length = end - start + 1;
return Array.from({ length }, (_, idx) =&gt; idx + start);
};
export const usePagination = ({
totalCount,
pageSize,
siblingCount = 1,
currentPage
}) =&gt; {
const paginationRange = useMemo(() =&gt; {
const totalPageCount = Math.ceil(totalCount / pageSize);
// Pages count is determined as siblingCount + firstPage + lastPage + currentPage + 2*DOTS
const totalPageNumbers = siblingCount + 5;
/*
If the number of pages is less than the page numbers we want to show in our
paginationComponent, we return the range [1..totalPageCount]
*/
if (totalPageNumbers &gt;= totalPageCount) {
return range(1, totalPageCount);
}
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
const rightSiblingIndex = Math.min(
currentPage + siblingCount,
totalPageCount
);
/*
We do not want to show dots if there is only one position left 
after/before the left/right page count as that would lead to a change if our Pagination
component size which we do not want
*/
const shouldShowLeftDots = leftSiblingIndex &gt; 2;
const shouldShowRightDots = rightSiblingIndex &lt; totalPageCount - 2;
const firstPageIndex = 1;
const lastPageIndex = totalPageCount;
if (!shouldShowLeftDots &amp;&amp; shouldShowRightDots) {
let leftItemCount = 3 + 2 * siblingCount;
let leftRange = range(1, leftItemCount);
return [...leftRange, DOTS, totalPageCount];
}
if (shouldShowLeftDots &amp;&amp; !shouldShowRightDots) {
let rightItemCount = 3 + 2 * siblingCount;
let rightRange = range(
totalPageCount - rightItemCount + 1,
totalPageCount
);
return [firstPageIndex, DOTS, ...rightRange];
}
if (shouldShowLeftDots &amp;&amp; shouldShowRightDots) {
let middleRange = range(leftSiblingIndex, rightSiblingIndex);
return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];
}
}, [totalCount, pageSize, siblingCount, currentPage]);
return paginationRange;
};

答案1

得分: 0

I think your memo isn't waiting for the result so you always get the result of the previous page loadData is an asynchronous function.

const currentReviewsData = useMemo(() => {
    const firstPageIndex = (currentPage - 1) * PageSize;
    const lastPageIndex = firstPageIndex + PageSize;
    loadData(filters.url, lastPageIndex, firstPageIndex)
    if (reviews) {
        return reviews
    } else {
        return []
    }
}, [currentPage]);

In my opinion, I don't think you should use a memo for currentReviewsData.

Try this:

const [currentReviewsData, setCurrentReviewsData] = useState([]);

useEffect(() => {
  if (typeof currentPage !== "undefined") {
    const firstPageIndex = (currentPage - 1) * PageSize;
    const lastPageIndex = firstPageIndex + PageSize;
    loadData(filters.url, lastPageIndex, firstPageIndex).then((reviews) => {
      setCurrentReviewsData(reviews);
    });
  }
}, [currentPage]);
英文:

I think your memo isn't waiting for the result so you always get the result of the previous page loadData is an asynchronous function.

    const currentReviewsData = useMemo(() =&gt; {
const firstPageIndex = (currentPage - 1) * PageSize;
const lastPageIndex = firstPageIndex + PageSize;
loadData(filters.url, lastPageIndex, firstPageIndex)
if (reviews) {
return reviews
} else {
return []
}
}, [currentPage]);

In my opinion I don't think you should use a memo for currentReviewsData.

Try this:

const [currentReviewsData, setCurrentReviewsData] = useState([]);
useEffect(() =&gt; {
if (typeof currentPage !== &quot;undefined&quot;) {
const firstPageIndex = (currentPage - 1) * PageSize;
const lastPageIndex = firstPageIndex + PageSize;
loadData(filters.url, lastPageIndex, firstPageIndex).then((reviews) =&gt; {
setCurrentReviewsData(reviews);
});
}
}, [currentPage]);
</details>

huangapple
  • 本文由 发表于 2023年3月9日 19:48:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684191.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定