javascript - React 钩子值正确呈现但未在 addEventListener 的回调函数中更新
问题描述
我正在功能组件中使用钩子实现无限滚动,我遇到了一个问题,我无法访问滚动事件回调函数中的更新值,这是我的代码:
// Get a hook function
const {useState, useEffect} = React;
const initItems = ['First', 'Second','Third','Fourth','Fifth']
const Example = ({title}) => {
const [posts, setPosts] = useState({
data: [],
page: 1
});
console.log('FN RENDER')
const handleScroll = (e) => {
const { scrollHeight, scrollTop, clientHeight } = e.target
const bottom = scrollHeight - scrollTop === clientHeight;
if (bottom) {
console.log('page', posts.page) // page stays 1
const nextPage = posts.page + 1
setPosts(p => ({
data: [...p.data, 'Append'],
page: p.page + 1
}))
}
}
useEffect(() => {
console.log('USEEFFECT RENDER')
setPosts(p => ({
data: initItems,
page: 1
}))
//using ScrollBox for demo, originally I'm handling the scroll event on the document: document.addEventListener
document.getElementById("ScrollBox").addEventListener('scroll',handleScroll);
return () => document.getElementById("ScrollBox").removeEventListener('scroll', handleScroll);
}, []);
return (
<div>
<p>Page:{posts.page}</p>
<div id="ScrollBox" class="scroll-box">
{
posts.data.map(k=> <p>{k} </p>)
}
</div>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
#ScrollBox{
border:1px solid red;
height:100px;
overflow:auto;
width:400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
如果您查看控制台,则在正确呈现时,值会page
保持不变。1
我曾经useEffect
附上事件。我怎样才能在里面获得正确的更新值handleScroll
?
- 编辑 -
如何在 的回调中获取更新的值addEventListener
?#ScrollBox
对于问题演示,我需要检测 scroll on document
,这就是我使用事件侦听器的原因。
解决方案
该useEffect
函数仅在第二个参数发生更改时触发。由于您有一个空的第二个参数,因此它永远不会更新,并且由于它永远不会更新,因此无论您更新多少次状态,您的事件处理程序都会从第一次渲染中保持陈旧的闭包。
您可以通过直接在渲染函数内部而不是在useEffect
. 无论如何,您都不应该在 react 中进行直接的 DOM 操作。
// Get a hook function
const {useState, useEffect} = React;
const initItems = ['First', 'Second','Third','Fourth','Fifth']
const Example = ({title}) => {
const [posts, setPosts] = useState({
data: [],
page: 1
});
console.log('FN RENDER')
const handleScroll = (e) => {
const { scrollHeight, scrollTop, clientHeight } = e.target
const bottom = scrollHeight - scrollTop === clientHeight;
if (bottom) {
console.log('page', posts.page) // page stays 1
const nextPage = posts.page + 1
setPosts(p => ({
data: [...p.data, 'Append'],
page: p.page + 1
}))
}
}
useEffect(() => {
console.log('USEEFFECT RENDER')
// <!-- No event handler here -->
setPosts(p => ({
data: initItems,
page: 1
}))
}, []);
return (
<div>
<p>Page:{posts.page}</p>
<!-- NOTE THE EVENT HANDLER HERE -->
<div id="ScrollBox" class="scroll-box"
onScroll={handleScroll}
>
{
posts.data.map(k=> <p>{k} </p>)
}
</div>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
#ScrollBox{
border:1px solid red;
height:100px;
overflow:auto;
width:400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
推荐阅读
- python - 芹菜的性能问题
- java - 如何在 Apache Ignite 中查找正在运行的服务器或客户端 ip 及其端口
- c# - Secondwindow 无法访问 Mainwindow 的文本框
- pandas - 新列中的组计数
- excel - How can I convert a number in a cell to time format when sending this cell via email?
- php - PHP 打印 - 调用未定义的函数 printer_list()
- electron - 为什么 Electron-Angular 项目在构建时会出现 GL ERROR
- node.js - 使用 nodejs 包装时,Cypress.io 找不到规范
- javascript - 如何在数组中对数组的第二个值进行排序?
- c# - 语音识别语义解释 UWP