React中如何更新document.body.offsetHeight并实现滚动加载?
document.body.offsetHeight After Loading Data Great question! This is a super common gotcha with infinite scroll in React—your scroll listener is checking the body height before React has finished rendering the new data you just loaded, so it’s still using the old value. Let’s walk through the fixes step by step:
1. First, Clean Up Your Scroll Listener (Critical!)
Right now, your effect isn’t removing the scroll listener when the component unmounts or when state changes. This leads to duplicate listeners firing, which can cause weird behavior like multiple load requests at once. Update your effect to include a cleanup function:
React.useEffect(() => { const handleScroll = () => { if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight && !state.more) { getAscii(state.page, 21, dispatch) console.log("you're at the bottom of the page", state.page) } } window.addEventListener('scroll', handleScroll) // Clean up the listener when component unmounts or state changes return () => window.removeEventListener('scroll', handleScroll) }, [state])
2. Wait for the DOM to Update Before Checking Height
React updates the DOM asynchronously after state changes. When your getAscii call finishes and updates state, the new data hasn’t rendered yet—so document.body.offsetHeight is still the old value. Use requestAnimationFrame to delay your height check until the next browser repaint, which ensures the DOM has updated:
const handleScroll = () => { // Exit early if we're already loading more data if (state.more) return; requestAnimationFrame(() => { // Add a small buffer (10px) to avoid missing the bottom due to browser rendering quirks const isAtBottom = (window.innerHeight + window.scrollY) >= document.body.offsetHeight - 10; if (isAtBottom) { getAscii(state.page, 21, dispatch); console.log("you're at the bottom of the page", state.page); } }); };
3. Use a Ref for More Reliable Height Tracking (Even Better!)
Relying on document.body.offsetHeight can be flaky if your page has fixed headers, footers, or other elements that affect the body’s height. Instead, attach a ref directly to your list container and check its height—this gives you a precise measurement of your scrollable content:
// Create a ref for your list container const listContainerRef = React.useRef(null); const handleScroll = () => { if (state.more) return; requestAnimationFrame(() => { const container = listContainerRef.current; if (!container) return; // Calculate if we've reached the bottom of the list container const containerBottom = container.offsetTop + container.offsetHeight; const isAtBottom = (window.innerHeight + window.scrollY) >= containerBottom - 10; if (isAtBottom) { getAscii(state.page, 21, dispatch); console.log("you're at the bottom of the page", state.page); } }); }; // Attach the ref to your list in JSX return ( <div ref={listContainerRef}> {/* Your rendered list items go here */} {state.data.map(item => <div key={item.id}>{item.content}</div>)} </div> );
4. Double-Check Your state.more Flag
Make sure your getAscii function is correctly updating the more state to prevent duplicate requests:
- When you start loading data, set
more: true - When the data finishes loading (and is added to your state), set
more: false
This ensures that while new data is being fetched, your scroll listener won’t trigger another request before the DOM has a chance to update.
内容的提问来源于stack exchange,提问作者Hypothesis

