为什么我的函数不能读取组件状态的实际值?
Why can't my function read the actual value of my component's state?
对于一个学校项目,我的团队正在构建一个 table,其中通过数据库调用填充了城市数据。
table-组件的骨架是这样的:
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>
}
table 具有 "infinite-scrolling" 功能,因此当您滚动到页面底部时,它会打印 "Show more rows!"
和 运行s fetchData(pageNum)
获取更多数据。此时,在初始获取之后,pageNum
-变量应该为 1 或更多,但由于某种原因,该函数的行为就好像它是 0。我将 pageNum
-变量显示在JSX,我可以看到它是 1
,但是当我 运行 它时它仍然打印出 "page is false 0"
。
当我尝试 google 这个问题时,似乎唯一类似的事情可能是我在使用 setPageNum 后(重绘之前)过早地尝试读取 useState 变量,但事实并非如此据我所知,这里的情况。我在两次尝试之间给了它足够的时间,它总是说 pageNum
为零。
关于我做错了什么的任何想法,以及这在任何方面有何意义?
感谢您的帮助!
编辑:刚刚尝试了我编写的代码,它似乎可以工作——但是我拥有的完整代码不起作用。任何人对与此相关的问题有任何想法,即使上面的代码可能有效?
EDIT2:我在fetchData
-函数中添加了一个console.log(pageNum)
,并测试了一下,似乎我在useState(VALUE)
中输入的初始值就是什么正在打印。这让 NO 对我有意义。
帮助。
EDIT3:添加了 await,实际代码中已经有了它
EDIT4:我已经尝试了一段时间,但在使用 React 时意识到我可以将滚动监听器向下移动到 JSX 区域,然后它起作用了——出于某种原因。现在可以了。无法真正将任何答案标记为正确答案,但问题已有所解决。
感谢所有试图提供帮助的人,真的很感激。
这可能无法完全解决问题(如果没有更多上下文很难判断),但是使用 Effect 运行s every render,诸如此类 'initial' fetchData(0)
将 运行 每次更新,这可能会在 fetchData
.
中的条件中每次给你 page = 0
的结果
没有更多上下文很难说,但我有一个猜测。
尝试使用
setCities(value => [...value, ...jsonResponse])
而不是
setCities([...cities, ...jsonResponse])
还要确保使用 await 来解决请求的承诺,例如:
const jsonResponse = await ...
您可以通过控制台记录它以检查它们是否未决以及您是否获得正确的 属性 如果它是嵌套对象。
您的陈旧问题正在发生,因为 React 不知道您对组件状态的依赖性。
例如,useEffect
确保每次滚动时都会调用初始渲染范围内的 showMoreRows
值。这个 showMoreRows
的副本引用了 pageNum
的初始值,但是那个值是 "frozen" 在 closure 和函数一起并且不会在组件状态改变时改变.因此,滚动监听将不起作用,因为它需要知道 pageNum
.
的当前状态
您可以通过使用 callbacks to "hookify" showMoreRows
and fetchData
and declare their dependence on the component state. You must then declare the dependence of useEffect
on these callbacks and use a 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>
}
对于一个学校项目,我的团队正在构建一个 table,其中通过数据库调用填充了城市数据。 table-组件的骨架是这样的:
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>
}
table 具有 "infinite-scrolling" 功能,因此当您滚动到页面底部时,它会打印 "Show more rows!"
和 运行s fetchData(pageNum)
获取更多数据。此时,在初始获取之后,pageNum
-变量应该为 1 或更多,但由于某种原因,该函数的行为就好像它是 0。我将 pageNum
-变量显示在JSX,我可以看到它是 1
,但是当我 运行 它时它仍然打印出 "page is false 0"
。
当我尝试 google 这个问题时,似乎唯一类似的事情可能是我在使用 setPageNum 后(重绘之前)过早地尝试读取 useState 变量,但事实并非如此据我所知,这里的情况。我在两次尝试之间给了它足够的时间,它总是说 pageNum
为零。
关于我做错了什么的任何想法,以及这在任何方面有何意义?
感谢您的帮助!
编辑:刚刚尝试了我编写的代码,它似乎可以工作——但是我拥有的完整代码不起作用。任何人对与此相关的问题有任何想法,即使上面的代码可能有效?
EDIT2:我在fetchData
-函数中添加了一个console.log(pageNum)
,并测试了一下,似乎我在useState(VALUE)
中输入的初始值就是什么正在打印。这让 NO 对我有意义。
帮助。
EDIT3:添加了 await,实际代码中已经有了它
EDIT4:我已经尝试了一段时间,但在使用 React 时意识到我可以将滚动监听器向下移动到 JSX 区域,然后它起作用了——出于某种原因。现在可以了。无法真正将任何答案标记为正确答案,但问题已有所解决。
感谢所有试图提供帮助的人,真的很感激。
这可能无法完全解决问题(如果没有更多上下文很难判断),但是使用 Effect 运行s every render,诸如此类 'initial' fetchData(0)
将 运行 每次更新,这可能会在 fetchData
.
page = 0
的结果
没有更多上下文很难说,但我有一个猜测。 尝试使用
setCities(value => [...value, ...jsonResponse])
而不是
setCities([...cities, ...jsonResponse])
还要确保使用 await 来解决请求的承诺,例如:
const jsonResponse = await ...
您可以通过控制台记录它以检查它们是否未决以及您是否获得正确的 属性 如果它是嵌套对象。
您的陈旧问题正在发生,因为 React 不知道您对组件状态的依赖性。
例如,useEffect
确保每次滚动时都会调用初始渲染范围内的 showMoreRows
值。这个 showMoreRows
的副本引用了 pageNum
的初始值,但是那个值是 "frozen" 在 closure 和函数一起并且不会在组件状态改变时改变.因此,滚动监听将不起作用,因为它需要知道 pageNum
.
您可以通过使用 callbacks to "hookify" showMoreRows
and fetchData
and declare their dependence on the component state. You must then declare the dependence of useEffect
on these callbacks and use a 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>
}