更新每页结果仅在分页反应的第一页有效。

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

Updating results per page only working on first page of pagination-react

问题

我可以让我的分页正常工作,但是当我想让用户更改每页显示的项目数量时,它只对第一页进行分页,并在第二页显示剩余的结果。

我还不断收到一个错误,说我的 pageCount 属性不是整数,需要使用 Math.ceil()。但我不确定在哪里使用它。

// pagination
// 设置为0,因为如果设置为1,它不会显示所有数据
const [currentPage, setCurrentPage] = useState(0);
const [productPerPage, setProductPerPage] = useState(30);
// const [itemOffset, setItemOffset] = useState(0);
const pageCount = Math.ceil(products.length / productPerPage);

const handleChanges = (e) => {
  setProductPerPage(e.target.value);
  console.log(pageCount);
  console.log(productPerPage);
}

const pagesVisited = currentPage * productPerPage;

在你的代码中,你已经正确地使用了 Math.ceil() 来计算 pageCount,这是为了确保页数是整数。其他部分似乎也没有问题,但如果你仍然遇到问题,可能需要进一步检查其他与分页相关的部分的实现,以确保它们与期望的行为一致。希望这可以帮助你解决问题!

英文:

I am able to make my pagination work as it should, however when I want the user to change the amount of items they see each page, it only paginates the first page and shows the remaining of the results on the second page.

I also keep getting an error that my pageCount prop is not an integer and I need to use Math.ciel().However I'm confused as where I need to use it.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { useContext, useState } from &#39;react&#39;;
import Searchbar from &#39;../Components/Searchbar&#39;;
import OptionButtons from &#39;../Components/OptionButtons&#39;;
import { AppContext } from &#39;../Context/Context&#39;;
import { FontAwesomeIcon } from &#39;@fortawesome/react-fontawesome&#39;;
import { faBasketShopping } from &#39;@fortawesome/free-solid-svg-icons&#39;;
import { Link } from &#39;react-router-dom&#39;;
import useAxios from &#39;../Hooks/useAxios&#39;;
import savedHook from &#39;../Hooks/savedHook&#39;;
import PriceSlider from &#39;../Components/PriceSlider&#39;;
import BrandList from &#39;../Components/BrandList&#39;;
import Pagination from &#39;react-paginate&#39;
import Drawer from &#39;react-modern-drawer&#39;
import Accordion from &#39;../Components/Accordion&#39;;
import &#39;react-modern-drawer/dist/index.css&#39;
import &#39;../Assets/Styles/Shop.css&#39;
function Shop() {
// States //////////////////////////////////////////////////////////////
const { products, setProducts, isLoading, serverErr, getProductsByBrand,
getProductsByType, selectAProduct, error, filterProduct, priceRangeProducts, openFilterDrawer, filterDrawer } = useAxios(&#39;https://makeup-api.herokuapp.com/api/v1/products.json&#39;)
// saved icon to shaded
const { likedIndex, changeIcon } = savedHook()
const accordionData = [
{
&#39;id&#39;: 1,
&#39;heading&#39;: &#39;Price Range&#39;,
&#39;content&#39;: &lt;PriceSlider onSlider={priceRangeProducts} /&gt;
},
{
&#39;id&#39;: 2,
&#39;heading&#39;: &#39;Brand&#39;,
&#39;content&#39;: &lt;BrandList brandDropDown={getProductsByBrand} /&gt;
}
]
// useContext for the add to cart 
const Cartstate = useContext(AppContext)
const dispatch = Cartstate.dispatch;
// Usecontext for the saved array as it uses a different function
const Savestate = useContext(AppContext)
const saveDispatch = Savestate.saveDispatch
// pagination 
// set to 0 because if I set it to 1 then it doesn&#39;t show all the data
const [currentPage, setCurrentPage] = useState(0)
const [productPerPage, setProductPerPage] = useState(30)
// const [itemOffset, setItemOffset] = useState(0);
const pageCount = Math.ceil(products.length / productPerPage);
const handleChanges = (e) =&gt; {
setProductPerPage(e.target.value)
console.log(pageCount)
console.log(productPerPage)
}
const pagesVisited = currentPage * productPerPage
// How I want the data to be shown on the page
const displayProducts = products.slice(
pagesVisited, pagesVisited + productPerPage
)
.map((item, index) =&gt; {
return (
&lt;div className=&#39;singleCard h-full flex flex-col mx-1 transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-100 hover: duration-300 hover:shadow-lg&#39; key={item.id}&gt;
&lt; button className=&#39;mx-1 my-1&#39; value={item.brand + item.product_type} onClick={() =&gt; { changeIcon(index); saveDispatch({ type: &#39;SAVE&#39;, saveIt: item }) }}&gt;
{likedIndex[index] ?
(
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; className=&quot;redHeart w-6 h-6&quot;&gt;
&lt;path d=&quot;M11.645 20.91l-.007-.003-.022-.012a15.247 15.247 0 01-.383-.218 25.18 25.18 0 01-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0112 5.052 5.5 5.5 0 0116.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 01-4.244 3.17 15.247 15.247 0 01-.383.219l-.022.012-.007.004-.003.001a.752.752 0 01-.704 0l-.003-.001z&quot; /&gt;
&lt;/svg&gt;
)
: (
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; strokeWidth=&quot;1.5&quot; stroke=&quot;currentColor&quot; className=&quot;w-6 h-6&quot; &gt;
&lt;path strokeLinecap=&quot;round&quot; strokeLinejoin=&quot;round&quot; d=&quot;M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z&quot; /&gt;
&lt;/svg&gt;
)
}
&lt;/button&gt;
&lt;Link to={`/product/${item.id}`} name={item.brand}&gt;
&lt;img className=&#39;productImg ml-8 mb-2 md:ml-8 xl:ml-14&#39; src={item.api_featured_image} alt={item.brand + item.product_type}&gt;&lt;/img&gt;
{/* To display the brand name with as sentence case */}
&lt;div className=&#39;productText px-2 flex flex-col content-end md:px-1 &#39;&gt;
&lt;p className=&#39;productType&#39;&gt;{item?.product_type ? item.product_type.charAt(0) + item.product_type.slice(1).toLowerCase().split(&#39;_&#39;).join(&#39; &#39;) : item.product_type}&lt;/p&gt;
&lt;p className=&#39;productBrand&#39;&gt;
{item?.brand ? item.brand.charAt(0).toUpperCase() + item.brand.slice(1).toLowerCase() : item.brand} &lt;/p&gt;
&lt;p className=&#39;productName&#39;&gt;{item?.name ? item.name.charAt(0).toUpperCase() + item.name.slice(1).toLowerCase() : item.name}&lt;/p&gt;
&lt;/div&gt;
&lt;/Link&gt;
&lt;div className=&#39;flex flex-row mt-auto mx-2 my-2&#39;&gt;
&lt;div className=&#39;mr-auto mt-auto&#39;&gt;
&lt;p className=&#39;productPriceShop&#39;&gt;&lt;span className=&#39;circleShadow &#39;&gt;&#163;{Number(item.price).toFixed(2)}&lt;/span&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;div className=&#39;addToCart ml-auto mt-auto &#39;&gt;
&lt;button className=&#39;basketProduct&#39; onClick={() =&gt; dispatch({ type: &#39;ADD&#39;, payload: item })}&gt;
&lt;FontAwesomeIcon icon={faBasketShopping} /&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
)
})
// calucates total pages need for all the data with how many items to be shown each page
// Math.ceil rounds the number of pages to a whole integer
//callback function invoked with the updated page value when the page is changed.
const changePage = ({ selected }) =&gt; {
setCurrentPage(selected)
console.log(pagesVisited)
console.log(selected)
}
const sortThis = (e) =&gt; {
const sorting = e.target.value
const productList = [...products]
const prices = productList.sort((a, b) =&gt; {
return sorting === &#39;asc&#39; ? a.price - b.price : b.price - a.price
});
setProducts(prices)
}
return (
&lt;&gt;
&lt;div className=&#39;shopTopBanner&#39;&gt;
&lt;h1&gt;Cosmetics for you&lt;/h1&gt;
&lt;ol className=&#39;routeProductPage flex flex-row mr-2&#39;&gt;
&lt;li&gt;&lt;Link to=&#39;/&#39;&gt;Home/&lt;/Link&gt;&lt;/li&gt;
&lt;li&gt;&lt;Link to=&#39;/shop&#39;&gt;Shop&lt;/Link&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div className=&#39;shopColumn&#39;&gt;
&lt;div className=&#39;leftShopColumn&#39;&gt;
&lt;div className=&#39;searchBar md:hidden&#39;&gt;
&lt;Searchbar
onSearch={getProductsByBrand}
onFilter={getProductsByType}
onInput={filterProduct}
/&gt;
&lt;/div&gt;
&lt;div className=&#39;priceSlider hidden md:inline-block&#39;&gt;
&lt;PriceSlider
onSlider={priceRangeProducts}&gt;&lt;/PriceSlider&gt;
&lt;/div&gt;
&lt;div className=&#39;productTypeButtons&#39;&gt;
&lt;OptionButtons onButton={selectAProduct} /&gt;
&lt;/div&gt;
&lt;div className=&#39;mobileSortMenu flex flex-row md:hidden&#39;&gt;
&lt;div&gt;
&lt;button onClick={openFilterDrawer}&gt;
More Options
&lt;/button&gt;
&lt;/div&gt;
&lt;div className=&#39;productPerPageMobile&#39;&gt;
&lt;select
value={productPerPage}
onChange={handleChanges}&gt;
&lt;option defaultValue&gt;Products per page&lt;/option&gt;
&lt;option value={5}&gt;
5 products
&lt;/option&gt;
&lt;option value={10}&gt;
10 products
&lt;/option&gt;
&lt;option value={20}&gt;
20 products
&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;
&lt;div className=&#39;sortingDropdownMobile&#39;&gt;
&lt;select onChange={sortThis}&gt;Sort it out
&lt;option defaultValue&gt;Sort&lt;/option&gt;
&lt;option value={&#39;asc&#39;}&gt;Ascending&lt;/option&gt;
&lt;option value={&#39;desc&#39;}&gt;Descending&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;
&lt;/div&gt;
{filterDrawer ?
&lt;&gt;
&lt;Drawer
open={filterDrawer}
onClose={openFilterDrawer}
direction=&#39;bottom&#39;&gt;
&lt;div className=&#39;flex flex-row&#39;&gt;
&lt;h1&gt;Filter and Sort &lt;/h1&gt;
&lt;h1 onClick={openFilterDrawer}&gt;Close&lt;/h1&gt;
&lt;/div&gt;
&lt;div className=&#39;flex flex-col&#39;&gt;
&lt;ul className=&quot;accordion&quot;&gt;
{accordionData.map(({ heading, content }) =&gt; (
&lt;Accordion heading={heading} content={content} /&gt;
))}
&lt;/ul&gt;
&lt;/div&gt;
&lt;/Drawer&gt;
&lt;/&gt;
: null}
&lt;div className=&#39;listOfBrands hidden md:inline-block&#39;&gt;
&lt;BrandList brandDropDown={getProductsByBrand}&gt;&lt;/BrandList&gt;
&lt;/div&gt;
&lt;div className=&#39;sortingDropdown hidden md:inline-block&#39;&gt;
&lt;select onChange={sortThis}&gt;Sort it out
&lt;option defaultValue&gt;Sort&lt;/option&gt;
&lt;option value={&#39;asc&#39;}&gt;Ascending&lt;/option&gt;
&lt;option value={&#39;desc&#39;}&gt;Descending&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;
&lt;div className=&#39;productsPerPage hidden md:inline-block&#39;&gt;
&lt;select
value={productPerPage}
onChange={handleChanges}&gt;
&lt;option defaultValue&gt;Products per page&lt;/option&gt;
&lt;option value={5}&gt;
5 products
&lt;/option&gt;
&lt;option value={10}&gt;
10 products
&lt;/option&gt;
&lt;option value={20}&gt;
20 products
&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;
&lt;button&gt;
Reset filters
&lt;/button&gt;
&lt;/div&gt;
&lt;div className=&#39;rightShopColumn&#39;&gt;
&lt;div className=&#39;searchBar hidden md:inline-block&#39;&gt;
&lt;Searchbar
onSearch={getProductsByBrand}
onFilter={getProductsByType}
onInput={filterProduct}
/&gt;
&lt;/div&gt;
{serverErr &amp;&amp; &lt;div&gt;{serverErr}&lt;/div&gt;}
{error ? &lt;div&gt;{error}&lt;/div&gt;:
&lt;div&gt;
{!isLoading ? &lt;&gt;
{products.length ?
&lt;&gt;
&lt;div className=&#39;shopCards grid grid-cols-2 flex-wrap py-4 mr-1 md:grid-cols-4 lg:grid-cols-4&#39;&gt;
{displayProducts}
&lt;/div&gt;
&lt;div className=&#39;flex flex-col&#39;&gt;
&lt;div &gt;
&lt;h1&gt; Showing {pagesVisited===0?1:pagesVisited} - {pagesVisited===0?30: pagesVisited*2} of {products.length} products&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;Pagination
previousLabel={&#39;Previous page&#39;}
// onChange={handleChanges}
nextLabel={&#39;Next page&#39;}
pageCount={pageCount}
pageClassName=&#39;pageNoneDisplay&#39;
breakClassName=&#39;pageNoneDisplay&#39;
onPageChange={changePage}
containerClassName={&#39;paginationBtns py-3&#39;}
previousLinkClassName={&#39;previousBtn&#39;}
nextLinkClassName={&#39;nextBtn&#39;}
disabledClassName={&#39;paginationDisbaled&#39;}
activeClassName={&#39;paginationActive&#39;}
pageRangeDisplayed={1}
marginPagesDisplayed={2}
/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/&gt;
: &lt;h1&gt;No results found&lt;/h1&gt;}
&lt;/&gt; :
&lt;&gt;
&lt;h1&gt;Loading...&lt;/h1&gt;
&lt;/&gt;
}
&lt;/div &gt;
}        &lt;/div&gt;
&lt;/div&gt;
&lt;/&gt;
)
}
export default Shop; 

<!-- end snippet -->

Would love some advice as I've been stuck on this for a couple of days now!

I have attached a simplified codesandbox:
https://github.com/chinapicke/shopit/blob/bb826719ea3a99bf1864ff676821e7dcc2d5ec5d/src/Pages/Shop.js

答案1

得分: 0

不运行您的代码,我认为您的根本问题是 productPerPage 的值 - 正如您已经指出的,它抱怨 pageCount 不是整数,但实际上问题在于使用原始的 event.target.value 来设置 setProductPerPage,而这是一个字符串 - 您需要使用 parseInt 或类似的方法来获取一个数字,并正确地将其设置为状态。

目前的结果是,您正在使用 slice() 来获取产品的一部分,似乎一旦到达第二页,您提供给 slice 的第二个参数不是有效的数字,因此最终切片如下:slice(pagesVisited),意味着只提供一个参数,因此在起始值之后接收所有元素,例如在这里显示

顺便提一下:要注意正确的命名,我很难理解您的代码,例如,pagesVisited 应该被称为 offset 等等 - 有一些良好的实践方法可以极大地提高代码的可维护性 更新每页结果仅在分页反应的第一页有效。

英文:

Without having run your code I'd say your underlying problem is the productPerPage value - as you already pointed out, it complains about pageCount not being an integer, but actually the issue is using setProductPerPage with the raw event.target.value, which is a string - you would need to use parseInt or something to get a number, and set it to the state correctly.

The current result is, you are using slice() to get a portion of your products, and it seems like, once you get to the 2nd page, the 2nd argument you are providing to slice is not a valid number, therefore you end up slicing like this: slice(pagesVisited), meaning only providing one argument, and therefore receiving all elements after the start value, as shown here for example.

Just a side note: be careful about proper naming, it was difficult for me to understand your code, for instance, pagesVisited should rather be called offset etc. - there are some good practises out there that will improve maintainability of your code immensely 更新每页结果仅在分页反应的第一页有效。

huangapple
  • 本文由 发表于 2023年8月5日 14:41:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76840440.html
匿名

发表评论

匿名网友

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

确定