最终结果需要排序并在结果顶部显示“reach-up-ads”,并且在滚动窗口而不单击按钮时获取更多结果。我刚刚添加了“加载更多”按钮进行测试。
现有实现不会在结果顶部显示“reach-up-ads”,并且在单击“加载更多”按钮时两次加载相同的数据。
前端
useEffect(()=>{
fetchPosts();
}, [skip])
const loadMore = () => {
setSkip(posts?.length);
}
const fetchPosts = async () => {
const { data } = await getMobilePosts(skip);
const filterData = await data?.filter(obj => obj.adPromote == "free-ad" || obj.adPromote == "reach-up-ad")
.sort((f,p)=>{
if (f.adPromote === 'reach-up-ad' && p.adPromote !== 'reach-up-ad') {
return -1;
} else if (f.adPromote !== 'reach-up-ad' && f.adPromote === 'reach-up-ad') {
return 1;
}
return 0;
})
.map(obj => {
return {
...obj,
title: `${obj.title} (${obj.features.condition})`,
location: `Posted On ${new Date(obj.createdAt).toDateString()}
}
});
setPosts(existing => [...existing, ...filterData]);
}
return (
<div>
{posts?.map((data, i) => {
return (
<ExchangeItemWideCard
key={i}
id={data._id}
title={data.title}
location={data.location}
/>
)
})}
<Button onClick={loadMore}>Load more</Button>
</div>
)
猫鼬
export async function getMobilePosts(skips: any) {
try{
const skip = skips ? Number(skips) : 0;
const DEFAULT_LIMIT = 10;
return await Post.find({expiredAt: {$gte: currentDate},status: 'live'},
"features.subCategory features.condition swapType.type swapType.price createdAt features.mainCategory title location.district location.location photos adPromote status description postedBy notes")
.skip(skip)
.limit(DEFAULT_LIMIT)
.sort({ _id: -1 });
} catch(error: any) {
throw new Error(error as any);
}
}
我找到了这个简单的解决方案,无需使用任何 NPM 包。
场景是这样的,当用户滚动到选定的 div 区域时,仅从后端 mongoDB 数据库获取数据,然后用户滚动应该获取更多数据。我使用
IntersectionObserver
和 useRef
来确定 div 位置,然后使用 addEventListener
设置滚动事件。最终代码如下所示。
const [post, setPost] = useState([]);
const [skip, setSkip] = useState(0);
const [loadMore, setLoadMore] = useState(true);
const [scrolled, setScrolled]:any = useState();
const endRef = useRef();
useEffect(() => {
getData(loadMore);
setLoadMore(false);
}, [scrolled]);
useEffect(() => {
//user being scrolled to list section
const observer = new IntersectionObserver((entries) => {
const entry = entries[0];
setScrolled(entry.isIntersecting)
})
observer.observe(endRef.current)
const list = document.getElementById('list')
if(props.scrollable) {
// get list div properties if div is fixed height
list.addEventListener('scroll', (e) => {
const el = e.target; //documentElement
if(el.scrollTop + el.clientHeight === el.scrollHeight) {
setLoadMore(true);
}
});
} else {
// list has auto height
window.addEventListener('scroll', () => {
//now scrolling + browser height === list div height + if any indent of top of the page
if (window.scrollY + window.innerHeight === list.clientHeight + list.offsetTop) {
setLoadMore(true);
}
});
}
return () => {
window.removeEventListener('scroll', this);
}
}, []);
useEffect(() => {
const list = document.getElementById('list');
if(list.clientHeight <= window.innerHeight && list.clientHeight) {
setLoadMore(true);
}
}, [post]);
const getData = async (load) => {
if(load){
//fetch data from back-end
}
}
return (
<div id='list' style={{maxHeight: '30%'}} ref={endRef}>
{post?.map((data, i) => {})}
</div>
)