尽管在 React 中更新了状态,但方法没有获得正确的 useState 值
Posted
技术标签:
【中文标题】尽管在 React 中更新了状态,但方法没有获得正确的 useState 值【英文标题】:Method not getting correct useState value despite updating state in React 【发布时间】:2021-01-09 07:56:19 【问题描述】:我正在尝试显示分页的学生信息的网站。例如,我有 12 个学生,我有 1-4 个分页项,因为我一次显示 3 个学生。
我在调用更新分页函数时遇到了问题。尽管我正确地递增它,但此方法中的计数器始终为 0。任何想法或指示将不胜感激。
import React, useState, useEffect from 'react';
function App()
let students = [
'name': 'Harry',
'name': 'Hermoine',
'name': 'Ron',
'name': 'Ginny',
'name': 'Snape',
'name': 'Bellatrix',
'name': 'Albus',
'name': 'Dudley',
'name': 'Petunia',
'name': 'Hagrid',
'name': 'Lee',
'name': 'James'
];
let [loaded, setLoaded] = useState(false);
let [pagination, setPagination] = useState([]);
let [limit, setLimit] = useState(3); // how many students are visible at a time
let [pages, setPages] = useState(Math.round(students.length/limit)); // amount of pages based on total students
let [currentPage, setCurrentPage] = useState(1); // the current page
let [pageCount, setPageCount] = useState(0); // counter used to increment/decrement pages in view
function updatePagination()
let tmpArray = [];
for(let i = pageCount; i < pages; i ++)
tmpArray.push(i+1);
// 1-3, 4-6 etc...
setPagination(tmpArray.slice(pageCount, pageCount + limit)); // this pageCount is always 0 despite me setting it on handleNext method
function handleNext()
setCurrentPage(currentPage + 1);
if(pageCount + limit === currentPage)
if(currentPage <= pages)
setPageCount(pageCount + limit);
updatePagination();
useEffect(() =>
updatePagination();
setLoaded(true);
, []);
return (
<main className=styles.app>
<div className=styles.student>
<h1>Three student cards</h1>
</div>
<ol className=styles.pagination>
<div className=styles.paginationContainer>
<button className=currentPage === 0 ? styles.prev + ' ' + styles.disabled : styles.prev>prev</button>
loaded && pagination.map((item, index) =>
return (
<li key=index className=styles.paginationItem>
<button className=currentPage === item ? styles.active : null>item</button>
</li>
)
)
<button onClick=() =>
handleNext()
className=currentPage === pages ? styles.next + ' ' + styles.disabled : styles.next>next</button>
</div>
</ol>
loaded &&
<div className=styles.info>
<p>Page Count: pageCount</p>
<p>Current Page: currentPage</p>
<p>Limit: limit</p>
<p>Pages: pages</p>
<p>Total Students: students.length</p>
<p>Pagination: pagination</p>
</div>
</main>
);
export default App;
【问题讨论】:
我无法在 snadbox 中运行您的示例,您可以制作一个代码nadbox 来解释问题所在吗?这是代码:codesandbox.io/s/adoring-hooks-wlcwm 这里是 Adir codesandbox.io/s/hook-issue-7b57d-7b57d,当我单击下一步按钮时,它转到第 2 页、第 3 页,这很好,问题是当它调用 updatePagination 函数时,调用此方法时 pageCount 始终为 0尽管更新了 handleNext 上的 pageCount 你能解释一下这个条件背后的原因吗:pageCount + limit === currentPage
inside handleNext
function?
Yousaf 用户出现以下分页 当用户达到 3 时,它应该将项目更新为 所以基本上当你到达最后一个可见项目时,你会增加计数和用它来切片数组。我有一个分页数组,它本质上是学生总数 1 2 3 4 5 6 7 8 9 10 11 12 使用下一个按钮时我将计数增加了限制,在这种情况下为 3,所以使用见 123,然后是 456 等。 .. 接受更简单的解决方案或想法
【参考方案1】:
以下是代码中的问题:
在handleNext()
函数中,您在调用setCurrentPage(...)
函数后立即使用currentPage
,但状态是异步更新的。所以currentPage
将是旧值而不是更新值。
另一个问题是,如果用户点击next
按钮三次,那么条件pageCount + limit === currentPage
将是true
,pageCount
将设置为pageCount + limit
,即3。这意味着循环在handleNext()
内部函数for (let i = pageCount; i < pages; i++) ...
只会执行一次。所以tmpArray
将只包含一个元素,即 4。
另外,由于调用 handleNext()
函数会根据之前的值更新 currentPage
,因此您应该通过将函数传递给 setCurrentPage()
函数来更新状态
setCurrentPage((page) => page + 1);
类似地转到上一页:
setCurrentPage((page) => page - 1);
这将确保正确更新状态。
编辑:
之前不清楚您为什么使用pageCount
,但您在评论中发布的演示清楚地说明了您想要实现的目标。
您在问题中提到的问题是pageCount
的值始终为零。查看您的代码,我认为您根本不需要pageCount
。
要实现所需的功能,您需要采取以下步骤:
要填充pagination
数组,您可以使用useEffect
挂钩,该挂钩会在students
数组或limit
更改时执行。
useEffect(() =>
// set pagination
let arr = new Array(Math.ceil(students.length / limit))
.fill()
.map((_, idx) => idx + 1);
setPagination(arr);
setLoaded(true);
, [students, limit]);
要一次显示有限数量的学生,请创建一个函数,根据 currentPage
和 limit
对 students
数组进行切片。
const getPaginatedStudents = () =>
const startIndex = currentPage * limit - limit;
const endIndex = startIndex + limit;
return students.slice(startIndex, endIndex);
;
要显示等于limit
的有限页数,您不需要pageCount
。您可以创建一个函数,根据currentPage
和limit
对pagination
数组进行切片。此函数与第 2 步中创建的函数类似,但不同之处在于 startIndex
的计算方式。
const getPaginationGroup = () =>
let start = Math.floor((currentPage - 1) / limit) * limit;
let end = start + limit;
return pagination.slice(start, end);
;
创建将更改 currentPage
的函数
function goToNextPage()
setCurrentPage((page) => page + 1);
function goToPreviousPage()
setCurrentPage((page) => page - 1);
function changePage(event)
const pageNumber = Number(event.target.textContent);
setCurrentPage(pageNumber);
这就是您获得所需功能所需的全部内容。
演示
下面的代码 sn -p 显示一个例子:
const studentsData = [
name: "Harry" ,
name: "Hermoine" ,
name: "Ron" ,
name: "Ginny" ,
name: "Snape" ,
name: "Bellatrix" ,
name: "Albus" ,
name: "Dudley" ,
name: "Petunia" ,
name: "Hagrid" ,
name: "Lee" ,
name: "James" ,
name: "Lily" ,
name: "Remus" ,
name: "Voldemort" ,
name: "Dobby" ,
name: "Lucius" ,
name: "Sirius"
];
function Student( name )
return (
<div className="student">
<h3>name</h3>
</div>
);
function App()
let [students] = React.useState(studentsData);
let [pagination, setPagination] = React.useState([]);
let [loaded, setLoaded] = React.useState(false);
let [limit] = React.useState(3);
let [pages] = React.useState(Math.round(students.length / limit));
let [currentPage, setCurrentPage] = React.useState(1);
function goToNextPage()
setCurrentPage((page) => page + 1);
function goToPreviousPage()
setCurrentPage((page) => page - 1);
function changePage(event)
const pageNumber = Number(event.target.textContent);
setCurrentPage(pageNumber);
React.useEffect(() =>
// set pagination
let arr = new Array(Math.ceil(students.length / limit))
.fill()
.map((_, idx) => idx + 1);
setPagination(arr);
setLoaded(true);
, [students, limit]);
const getPaginatedStudents = () =>
const startIndex = currentPage * limit - limit;
const endIndex = startIndex + limit;
return students.slice(startIndex, endIndex);
;
const getPaginationGroup = () =>
let start = Math.floor((currentPage - 1) / limit) * limit;
let end = start + limit;
return pagination.slice(start, end);
;
return (
<main>
<h1>Students</h1>
loaded && (
<div className="studentsContainer">
getPaginatedStudents().map((s) => (
<Student key=s.name ...s />
))
</div>
)
<ol className="pagination">
<div className="paginationContainer">
<button
onClick=goToPreviousPage
className=currentPage === 1 ? "prev disabled" : "prev"
>
prev
</button>
loaded &&
getPaginationGroup().map((item, index) =>
return (
<li key=index className="paginationItem">
<button
onClick=changePage
className=currentPage === item ? "active" : null
>
item
</button>
</li>
);
)
<button
onClick=goToNextPage
className=currentPage === pages ? "next disabled" : "next"
>
next
</button>
</div>
</ol>
</main>
);
ReactDOM.render(<App/>, document.getElementById('root'));
h1 margin: 0;
.studentsContainer
display: flex;
background: #efefef;
padding: 15px 10px;
margin: 5px 0;
.student
flex-grow: 1;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
text-align: center;
max-width: 450px;
margin: 0 5px;
.pagination
position: relative;
padding: 0;
.paginationContainer
align-items: center;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(40px, auto));
grid-column-gap: .65rem;
justify-content: center;
justify-items: center;
max-width: 100%;
width: 100%;
position: relative;
.paginationItem
height: 40px;
width: 40px;
user-select: none;
list-style: none;
.prev, .next
user-select: none;
cursor: pointer;
background: transparent;
border: none;
outline: none;
.prev.disabled, .next.disabled
pointer-events: none;
opacity: .5;
button
padding: .65rem;
display: block;
height: 100%;
width: 100%;
border-radius: 50%;
text-align: center;
border: 1px solid #ccc;
outline: none;
cursor: pointer;
button.active
background: rgba(black, .25);
border: none;
color: #777;
pointer-events: none;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
您也可以在codesandbox上查看此演示。
【讨论】:
Yousaf,非常感谢您的建议和建议。我根据您的反馈和示例进行了一些调整。你可以在这里查看我的最新版本codesandbox.io/s/hook-issue-7b57d-7b57d。我关于如何更新我的页数的问题仍然有效。我在下一个和上一个句柄中硬编码了页数限制,以清楚地传达我想要完成的任务。在您的示例中,分页将显示所有学生/限制,但在某些情况下,我有很多学生同时显示它们会占用大量水平空间。以上是关于尽管在 React 中更新了状态,但方法没有获得正确的 useState 值的主要内容,如果未能解决你的问题,请参考以下文章