我想在 React 中创建分页。所有数据来自商店。在这段代码中,我想实现搜索引擎。这次我没有这个,但我写了模拟那个的搜索方法。好的,它可以工作,但是 - 在我单击 hello 后,它仅显示类别 2 中的项目,但它始终显示相同的页面(在我的情况下为 3)。如果我再点击 2 次,它只显示 1 页。我在搜索中添加了 setCountItems 和 setPages,因为这个钩子不会自动更新。
import React, { useEffect, useState, useRef } from 'react'
import { connect} from 'react-redux'
import Article from './article'
const ArticlesContainer = ({ articles }) => {
const [allItems, setAllItems] = useState(articles.list);
const [pageNumber, setPageNumber] = useState(1);
const [perSite, setPerSite] = useState(10);
const [totalItems, setCountItems] = useState(allItems.length);
const from = (pageNumber - 1) * perSite;
const to = ((pageNumber - 1) * perSite) + perSite;
const [pages, setPages] = useState(Math.ceil(totalItems / perSite));
const handlePageClick = (i) => {
setPageNumber(i);
}
const search = () => {
setAllItems(allItems.filter(x => x.category=== 2 ));
setCountItems(allItems.length);
setPages(Math.ceil(totalItems / perSite));
}
const Pagination = ({pages}) => {
let list = []
for(let i = 1; i<=pages; i++){
list.push(<li key={i} onClick={() => handlePageClick(i)}>{i}</li>)
}
return list;
}
return (
<React.Fragment>
<a onClick={search}>Hello</a>
{allItems.slice(from, to).map(article =>
<Article key={article.id} article={article} />
)}
<div className="row">
<ul>
<Pagination pages={pages} />
</ul>
</div>
</React.Fragment>
);
}
const mapStateToProps = state => ({
articles: state.articles
})
export default connect(mapStateToProps, null)(ArticlesContainer);
问题出在哪里?
答案 0 :(得分:1)
您似乎对 State 在 React 中的工作方式存在普遍误解。更新状态,无论是通过类中的 this.setState
还是通过 useState
钩子返回的“更新函数”,都不会“自动”改变相关的状态值。在类组件中,这是因为 React 的 setState
实现是如何工作的(它是异步的),但是对于 Hooks,如果你停下来思考它应该是非常明显的。 setAllItems
是一个函数,而 allItems
是一个数组 - 它们之间没有任何直接关系。调用 setAllItems
不会改变 allItems
的值 - 因为怎么会呢? allItems
只是一个变量,给它一个新值的唯一方法是直接对其进行变异或重新分配 - 显然调用一个单独的函数 setAllItems
,其参数不是 {{1} },不可能那样做。
它的作用是安排组件的重新渲染——也就是说,安排代表组件的函数的后续调用——并确保对应于 allItems
的 useState
调用随后将返回您设置的值。但这必然是一个相当间接的过程。特别是,allItems
将在组件的 next 渲染中具有您想要的值,但不会调用该 allItems
函数(直到用户再次单击该按钮),因此 search
调用不会以“正确”长度(过滤后的更新长度)自动触发。
在您的情况下,问题的解决方案非常简单。您通过引入太多状态变量使组件过于复杂,其中大多数状态变量相互依赖。而不是 setCountItems(allItems.length);
,只需输入 const [totalItems, setCountItems] = useState(allItems.length);
- 然后它会在每次渲染时自动重新计算为正确的值。您不需要 const totalItems = allItems.length;
函数,因为您知道它始终等于 setCountItems
- 它不会独立变化。
同样,您可以大大简化此组件中的其他许多内容,因为唯一可以独立变化并因此需要成为状态一部分的内容是文章列表和页码。这就是我重写您的组件的方式:
allItems.length