对于一个学校项目,我的团队正在构建一个表,该表通过数据库调用填充了城市数据。 表格组件的骨架是这样的:
import React, { useState } from 'react'
function Table(props) {
const [ cities, setCities ] = useState([])
const [ pageNum, setPageNum ] = useState(0)
useEffect(()=> { // this sets up the listener for the infinite scroll
document.querySelector(".TableComponent").onscroll = () => {
if (Math.ceil(table.scrollHeight - table.scrollTop) === table.clientHeight) showMoreRows()
}
//initial fetch
fetchData(0)
},[])
async function showMoreRows() {
console.log("Show more rows!")
await fetchData(pageNum)
}
async function fetchData(page) {
// some code, describing fetching
// EDIT2 start
console.log(pageNum)
// EDIT2 end
const jsonResponse = await {}// THE RESPONSE FROM THE FETCH
if(page) {
setCities([...cities, ...jsonResponse])
console.log("page is true", page)
setPageNum(pageNum + 1)
} else {
console.log("page is false", page) // this always runs and prints "page is false 0"
setCities([...cities, ...jsonResponse])
setPageNum(1)
}
}
return <div className="TableComponent"> { pageNum }
<!-- The rest of the component -->
</div>
}
该表具有“无限滚动”功能,因此,当您滚动到页面底部时,它将打印"Show more rows!"
并运行fetchData(pageNum)
以获取更多数据。此时,在初始获取后,pageNum
变量应为1或更大,但是由于某种原因,该函数的作用就像是0。我将pageNum
变量放在JSX,我可以看到它是1
,但是无论我何时运行它,它仍然会打印出"page is false 0"
。
当我尝试搜索该问题时,似乎唯一相似的事情可能是我尝试在使用setPageNum之后(重绘之前)过早读取useState-variable,但就目前而言并非如此我可以看到。我在尝试之间花了很多时间,它总是说pageNum
为零。
关于我在做什么错的任何想法,以及这在任何方面如何有意义?
感谢您的帮助!
编辑:刚刚尝试了我写过的代码,它似乎可以工作-但是我拥有的完整代码不起作用。即使上面的代码可行,对这个问题有任何想法吗?
EDIT2:我在console.log(pageNum)
函数中添加了fetchData
,并进行了一些测试,看来我在useState(VALUE)
的初始值中输入的内容都是正在打印的内容。这对我来说否很有意义。
帮助。
EDIT3:添加了一个等待,已经在真实代码中
EDIT4:我已经尝试了一段时间,但是意识到当我使用react时,我可以将我拥有的滚动侦听器移到JSX区域,然后由于某些原因它起作用了。现在可以使用了。不能真正将任何答案标记为正确的答案,但问题已得到解决。
感谢所有尝试提供帮助的人,非常感谢。
答案 0 :(得分:1)
由于您不了解您对组件状态的依赖性,因此发生了陈旧问题。
例如,useEffect
确保在每次滚动时都调用来自初始渲染范围的showMoreRows
的值。 showMoreRows
的此副本引用pageNum
的初始值,但是该值在closure中与函数一起被“冻结”,并且在组件状态不变时不会更改。因此,滚动侦听将无法正常工作,因为它需要知道pageNum
的当前状态。
您可以通过使用callbacks来“挂钩” showMoreRows
和fetchData
并声明它们对组件状态的依赖性来解决问题。然后,您必须声明useEffect
对这些回调的依赖性,并使用clean-up function处理多次调用的效果。
它看起来像这样(我没有尝试运行代码):
import React, { useState } from 'react'
function Table(props) {
const [ cities, setCities ] = useState([])
const [ pageNum, setPageNum ] = useState(0)
useEffect(()=> {
// Run this only once by not declaring any dependencies
fetchData(0)
}, [])
useEffect(()=> {
// This will run whenever showMoreRows changes.
const onScroll = () => {
if (Math.ceil(table.scrollHeight - table.scrollTop) === table.clientHeight) showMoreRows()
};
document.querySelector(".TableComponent").onscroll = onScroll;
// Clean-up
return () => document.querySelector(".TableComponent").onscroll = null;
}, [showMoreRows])
const showMoreRows = React.useCallback(async function () {
console.log("Show more rows!")
await fetchData(pageNum)
}, [fetchData, pageNum]);
const fetchData = React.useCallback(async function (page) {
// some code, describing fetching
// EDIT2 start
console.log(pageNum)
// EDIT2 end
const jsonResponse = await {}// THE RESPONSE FROM THE FETCH
if(page) {
setCities([...cities, ...jsonResponse])
console.log("page is true", page)
setPageNum(pageNum + 1)
} else {
console.log("page is false", page) // this always runs and prints "page is false 0"
setCities([...cities, ...jsonResponse])
setPageNum(1)
}
}, [setCities, cities, setPageNum, pageNum]);
return <div className="TableComponent"> { pageNum }
<!-- The rest of the component -->
</div>
}
答案 1 :(得分:0)
这可能无法完全解决问题(如果没有更多上下文,很难说清),但是useEffect运行every render,因此像“ initial” fetchData(0)
这样的事情将在每次更新时运行,可能会在page = 0
中的那个条件下每次给您fetchData
的结果。
答案 2 :(得分:0)
没有更多上下文很难说,但我有一个猜测。 尝试使用
setCities(value => [...value, ...jsonResponse])
代替
setCities([...cities, ...jsonResponse])
还要确保您使用等待来解决请求的承诺,例如:
const jsonResponse = await ...
您可以在控制台上对其进行日志记录,以检查它们是否未挂起,并且如果它是嵌套对象,则可以获取正确的属性。