如何在React中结合React Query实现组件入视口时才查询数据?
实现滚动到帖子时懒加载评论(React + React Query)
要解决一次性加载所有评论导致后端压力过大的问题,核心思路是结合Intersection Observer API检测帖子可见性,通过React Query的enabled参数控制评论查询的触发时机,仅当帖子进入用户视口时才加载对应评论。
具体实现步骤
- 给每个帖子组件添加DOM引用,用于监听可见性
- 使用Intersection Observer监听帖子元素是否进入视口
- 用状态变量标记帖子是否可见
- 在React Query的
useQuery中设置enabled为帖子可见状态,控制查询执行时机
修改后的代码
PostComponent 帖子组件
import React, { useState, useEffect, useRef } from 'react'; import { useQuery } from 'react-query'; const PostComponent = ({ post }) => { const [isVisible, setIsVisible] = useState(false); // 创建DOM引用,用于监听帖子元素 const postRef = useRef(null); useEffect(() => { // 初始化Intersection Observer const observer = new IntersectionObserver( ([entry]) => { // 当元素进入视口时,标记为可见并停止监听 if (entry.isIntersecting) { setIsVisible(true); observer.unobserve(entry.target); } }, { threshold: 0.1, // 元素10%可见时触发 // 可选优化:预加载,元素距离视口200px时就开始加载 // rootMargin: '200px' } ); if (postRef.current) { observer.observe(postRef.current); } // 组件卸载时清理监听,避免内存泄漏 return () => { if (postRef.current) { observer.unobserve(postRef.current); } }; }, []); // 仅当帖子可见时,才触发评论查询 const { data: comments, isLoading, error } = useQuery( ['comments', post.id], () => fetchComments(post.id), { enabled: isVisible } ); return ( <div ref={postRef} style={{ margin: '2rem 0', padding: '1rem', border: '1px solid #eee' }}> <h3>{post.title}</h3> <p>{post.body}</p> <div className="comments"> {isLoading && <p>加载评论中...</p>} {error && <p>加载评论失败,请稍后重试</p>} {comments && ( <div> <h4>评论 ({comments.length})</h4> {comments.map(comment => ( <div key={comment.id} style={{ margin: '0.5rem 0', padding: '0.5rem', background: '#f5f5f5' }}> <p><strong>{comment.name}</strong>: {comment.body}</p> </div> ))} </div> )} </div> </div> ); };
PostsPage 帖子页面组件
import React from 'react'; import { useQuery } from 'react-query'; import PostComponent from './PostComponent'; const PostsPage = () => { const { data: posts, isLoading, error } = useQuery('posts', fetchPosts); return ( <div style={{ maxWidth: '800px', margin: '0 auto' }}> {isLoading && <div>加载帖子中...</div>} {error && <div>加载帖子失败</div>} {posts && posts.map(post => ( <PostComponent key={post.id} post={post} /> ))} </div> ); };
关键细节说明
- Intersection Observer:浏览器原生API,高效监听元素是否进入视口,性能优于scroll事件,不会频繁触发回调。
- React Query
enabled参数:默认值为true,设置为isVisible后,仅当帖子可见时才执行评论查询,避免初始加载时一次性请求所有评论。 - 缓存机制:React Query会自动缓存已加载的评论,用户滚动回去时不会重复请求,既提升体验又减少后端压力。
- 清理监听:组件卸载时调用
unobserve,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Ushan Fernando
相关产品推荐
相关产品推荐

