使用 useState、Material-UI 和自定义挂钩对搜索结果进行分页时遇到问题
Having trouble paginating search results using useState, Material-UI and custom hook
我在 React 应用程序的页面上遇到分页问题。在页面上,当一个人在搜索栏中输入时(自然地)呈现搜索结果。我认为我的问题出在该页面的分页设置方式上。
只要用户在搜索任何其他内容之前单击返回第一页,分页就可以正常工作。例如,如果用户在第 3 页,然后在搜索栏中键入新内容,则除非用户在分页栏上再次单击 'page 1',否则不会显示新搜索。但是,如果他们在进行新搜索之前返回到初始搜索的第 1 页,则新搜索的第 1 页会正确显示。希望这是有道理的。这是出现问题的页面:
import React, { useState } from "react";
import Pagination from "@material-ui/core/Pagination";
import usePagination from "./usePagination.js";
export default function Main({reviews, web3}) {
const [search, setSearch] = useState("");
const [page, setPage] = useState(1);
const updateSearch = (event) => {
setSearch(event.target.value.substr(0, 20));
}
let filteredReviews = reviews.filter(
(review) => {
return review.restaurantName.indexOf(web3.utils.toHex(search)) !== -1;
});
let paginatedReviews = usePagination(filteredReviews, 2);
const handleChange = (e, p) => {
setPage(p);
paginatedReviews.jumpPage(p);
}
return (
<div className="container-fluid mt-5" style={{ minHeight: "100vh" }}>
<div className="row">
<main role="main" className="col-lg-12 ml-auto mr-auto" style={{ maxWidth: '500px' }}>
<div className="content mr-auto ml-auto">
<input type="text" className="form-control" value={search} onChange={updateSearch} />
{filteredReviews.length > 0 ? paginatedReviews.pageData().map((review, key) => {
return (
<>
<div key={key}>
// search result item
</div>
</>
)
})
{filteredReviews.length > 1
? <Pagination
count={paginatedReviews.maxPage}
page={page}
onChange={handleChange}
/>
: null
)
</div>
</main>
</div>
</div>
);
}
这里是 usePagination:
import { useState } from "react";
export default function usePagination(allReviews, perPage) {
const [currentPage, setCurrentPage] = useState(1);
const maxPage = Math.ceil(allReviews.length / perPage);
function pageData() {
const start = (currentPage - 1) * perPage;
const end = start + perPage
return allReviews.slice(start, end);
}
function jumpPage(page) {
const pageNumber = Math.max(1, page);
setCurrentPage((currentPage) => Math.min(pageNumber, maxPage));
}
return { jumpPage, pageData, currentPage, maxPage }
}
我想我可以通过将 setPage(1)
添加到 updateSearch
来解决我遇到的问题,以便让页面在每次新搜索时自动移至第 1 页,但事实并非如此工作,因为您仍然必须单击实际分页栏上的第 1 页才能显示结果。
编辑:我尝试在挂钩中重命名 currentPage
和 setCurrentPage
,以便它们共享与我页面上相同的名称,但这也没有用。
提前感谢您提供的任何帮助。如果您需要我详细说明任何事情,我会很乐意这样做。
如何在 useEffect 中更新页面?这样,您将确保所有挂钩都具有 运行 并且它们的 return 值是最新的(渲染后使用 Effect 运行s)。如果您在搜索查询的同时过早地重置页面,jumpPage 可能依赖于陈旧数据:您的搜索结果和内部 usePagination 值(如 maxPage)将没有机会重新计算。
这是一个基于您的 codesandbox 的工作示例:https://codesandbox.io/s/restless-dust-28351
请注意,要确保 useEffect 运行s 仅在搜索时更改,您需要将 jumpPage 包装在 useCallback 中,以便 jumpPage 函数引用保持不变。一般来说,我建议您对 return 从自定义挂钩中编辑的方法执行此操作。这样,这些方法可以更安全地在任何地方使用,包括作为 useEffect、useCallback 等的依赖项。
此外,我建议解构自定义挂钩 return 值,以便它们中的每一个都可以单独用作挂钩依赖项,如我上面示例中的 jumpPage。
我还从 App 中删除了页面状态,因为它已经在 usePagination 中进行了跟踪并从那里 returned。将 usePagination 作为封装所有分页内容的单一真实来源使事情变得更简单。简单是一个伟大的理想:)
最后,注意一点:最好不要将
纯粹用作垫片。它在没有提供任何有用语义的情况下使标记变得混乱,最好将间距问题留给 CSS.
祝你 React 工作顺利,你做得很好!
我在 React 应用程序的页面上遇到分页问题。在页面上,当一个人在搜索栏中输入时(自然地)呈现搜索结果。我认为我的问题出在该页面的分页设置方式上。
只要用户在搜索任何其他内容之前单击返回第一页,分页就可以正常工作。例如,如果用户在第 3 页,然后在搜索栏中键入新内容,则除非用户在分页栏上再次单击 'page 1',否则不会显示新搜索。但是,如果他们在进行新搜索之前返回到初始搜索的第 1 页,则新搜索的第 1 页会正确显示。希望这是有道理的。这是出现问题的页面:
import React, { useState } from "react";
import Pagination from "@material-ui/core/Pagination";
import usePagination from "./usePagination.js";
export default function Main({reviews, web3}) {
const [search, setSearch] = useState("");
const [page, setPage] = useState(1);
const updateSearch = (event) => {
setSearch(event.target.value.substr(0, 20));
}
let filteredReviews = reviews.filter(
(review) => {
return review.restaurantName.indexOf(web3.utils.toHex(search)) !== -1;
});
let paginatedReviews = usePagination(filteredReviews, 2);
const handleChange = (e, p) => {
setPage(p);
paginatedReviews.jumpPage(p);
}
return (
<div className="container-fluid mt-5" style={{ minHeight: "100vh" }}>
<div className="row">
<main role="main" className="col-lg-12 ml-auto mr-auto" style={{ maxWidth: '500px' }}>
<div className="content mr-auto ml-auto">
<input type="text" className="form-control" value={search} onChange={updateSearch} />
{filteredReviews.length > 0 ? paginatedReviews.pageData().map((review, key) => {
return (
<>
<div key={key}>
// search result item
</div>
</>
)
})
{filteredReviews.length > 1
? <Pagination
count={paginatedReviews.maxPage}
page={page}
onChange={handleChange}
/>
: null
)
</div>
</main>
</div>
</div>
);
}
这里是 usePagination:
import { useState } from "react";
export default function usePagination(allReviews, perPage) {
const [currentPage, setCurrentPage] = useState(1);
const maxPage = Math.ceil(allReviews.length / perPage);
function pageData() {
const start = (currentPage - 1) * perPage;
const end = start + perPage
return allReviews.slice(start, end);
}
function jumpPage(page) {
const pageNumber = Math.max(1, page);
setCurrentPage((currentPage) => Math.min(pageNumber, maxPage));
}
return { jumpPage, pageData, currentPage, maxPage }
}
我想我可以通过将 setPage(1)
添加到 updateSearch
来解决我遇到的问题,以便让页面在每次新搜索时自动移至第 1 页,但事实并非如此工作,因为您仍然必须单击实际分页栏上的第 1 页才能显示结果。
编辑:我尝试在挂钩中重命名 currentPage
和 setCurrentPage
,以便它们共享与我页面上相同的名称,但这也没有用。
提前感谢您提供的任何帮助。如果您需要我详细说明任何事情,我会很乐意这样做。
如何在 useEffect 中更新页面?这样,您将确保所有挂钩都具有 运行 并且它们的 return 值是最新的(渲染后使用 Effect 运行s)。如果您在搜索查询的同时过早地重置页面,jumpPage 可能依赖于陈旧数据:您的搜索结果和内部 usePagination 值(如 maxPage)将没有机会重新计算。
这是一个基于您的 codesandbox 的工作示例:https://codesandbox.io/s/restless-dust-28351 请注意,要确保 useEffect 运行s 仅在搜索时更改,您需要将 jumpPage 包装在 useCallback 中,以便 jumpPage 函数引用保持不变。一般来说,我建议您对 return 从自定义挂钩中编辑的方法执行此操作。这样,这些方法可以更安全地在任何地方使用,包括作为 useEffect、useCallback 等的依赖项。
此外,我建议解构自定义挂钩 return 值,以便它们中的每一个都可以单独用作挂钩依赖项,如我上面示例中的 jumpPage。
我还从 App 中删除了页面状态,因为它已经在 usePagination 中进行了跟踪并从那里 returned。将 usePagination 作为封装所有分页内容的单一真实来源使事情变得更简单。简单是一个伟大的理想:)
最后,注意一点:最好不要将
纯粹用作垫片。它在没有提供任何有用语义的情况下使标记变得混乱,最好将间距问题留给 CSS.
祝你 React 工作顺利,你做得很好!