我正在使用Intersection Observer来查看div元素是否在视口中,该视口实际上是页面的底部。在useEffect挂钩中,我要从Firestore提取博客并保存到state,然后滚动到最下面的第二个提取函数运行,这将提取另一个博客。我将以前的博客和新的博客的状态设置为Blog,但是以某种方式,以前的博客是空数组。 它仅输出新博客,而旧博客消失了。
getBlogs正在从Firestore获取文档,并使用获取的博客创建新数组。
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import BlogListItem from './BlogListItem';
import db from '../firebase/firebase';
import BlogFilters from './BlogFilters';
import loader from '../images/loader.gif';
import RecentFeed from './RecentFeed';
import BlogsContext from '../context/blogs-context';
let startDoc = null;
const getBlogs = docs => {
const blogs = [];
docs.forEach(doc => {
blogs.push({
id: doc.id,
...doc.data(),
});
});
startDoc = docs[docs.length - 1];
return blogs;
};
const firstFetchBlogs = async () => {
const data = await db.collection('blogs').orderBy('createdAt', 'desc').limit(5).get();
return getBlogs(data.docs);
};
const fetchBlogs = async () => {
const data = await db.collection('blogs').orderBy('createdAt', 'desc').startAfter(startDoc).limit(5).get();
return getBlogs(data.docs);
};
export const ReadBlogList = () => {
const [ blogs, setBlogs ] = useState([]);
const [ loading, setLoading ] = useState(true);
const [ smallLoading, setSmallLoading ] = useState(false);
const [ noMore, setNoMore ] = useState(false);
const scrollElement = React.useRef();
const paginateBlogs = () => {
setSmallLoading(true);
fetchBlogs()
.then(newBlogs => {
setBlogs([ ...blogs, ...newBlogs ]);
setSmallLoading(false);
})
.catch(() => {
setSmallLoading(false);
setNoMore(true);
});
};
const io = new IntersectionObserver(entries => {
const ratio = entries[0].intersectionRatio;
if (ratio > 0) {
paginateBlogs();
}
});
useEffect(() => {
let didCancel = false;
firstFetchBlogs().then(newBlogs => {
if (!didCancel) {
setBlogs(newBlogs);
setLoading(false);
io.observe(scrollElement.current);
}
});
return () => {
didCancel = true;
};
}, []);
return (
<div className="container read-blog-list">
<BlogFilters />
{loading && <img src={loader} alt="Loader" />}
{!loading && (
<BlogsContext.Provider value={{ blogs }}>
<div className="read-blog-list__content">
{blogs.length > 0 ? (
<div className="read-blog-list__blogs">
{blogs.map(blog => <BlogListItem to="read" key={blog.id} {...blog} />)}
<div ref={scrollElement} />
</div>
) : (
noMore && <p className="text-grey-darkest text-center text-xl">No more blogs</p>
)}
<RecentFeed />
{smallLoading && (
<div className="flex items-center justify-center">
<img className="w-12 h-12" src={loader} alt="Loader" />
</div>
)}
</div>
</BlogsContext.Provider>
)}
</div>
);
};
const mapStateToProps = state => ({
filters: state.filters,
});
export default connect(mapStateToProps)(ReadBlogList);