[英]React hooks value renders correctly but not updated inside a callback function of addEventListener
I'm implementing infinite scroll with hooks in a functional component, I'm having an issue where I'm unable to access the updated value inside the scroll event callback function, here's my code:我在功能组件中使用钩子实现无限滚动,我遇到了一个问题,我无法访问滚动事件回调 function 中的更新值,这是我的代码:
// 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>
If you look into the console, the value of page
stays 1
while it is rendered correctly.如果您查看控制台, page
的值在正确呈现时保持为1
。 I used useEffect
to attach the event.我使用useEffect
来附加事件。 How can I get the right updated value inside handleScroll
?如何在handleScroll
中获得正确的更新值?
-- Edit -- - 编辑 -
How to get the updated value inside the callback of addEventListener
?如何在addEventListener
的回调中获取更新的值? #ScrollBox
is for the question demo, I instead need to detect scroll on document
, which is the reason I'm using the event listener. #ScrollBox
用于问题演示,我需要检测document
上的滚动,这就是我使用事件侦听器的原因。
The useEffect
function only fires when the second parameter has changed. useEffect
function 仅在第二个参数发生更改时触发。 Since you have an empty second parameter, it will never update, and since it never updates, your event handler holds on to the stale closure from the first render no matter how many times you update the state.由于您有一个空的第二个参数,因此它永远不会更新,并且由于它永远不会更新,因此无论您更新 state 多少次,您的事件处理程序都会从第一次渲染开始保持陈旧的关闭。
You can fix your code by passing the the event listener directly inside the render function rather than in useEffect
.您可以通过在渲染 function 而不是在useEffect
中直接传递事件侦听器来修复您的代码。 You should not do direct DOM manipulation in react anyway.无论如何,您都不应该在 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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.