I'm at a loss here. I feel like I've been trying everything, and using the exact methods explained in other posts/tutorials everywhere. I understand that you need to use a cursor and set the first and last visible document so that you can start after the last, in the case of moving forward, and start BEFORE the first, in the case of moving backwards.
我在这里不知所措。我觉得我已经尝试了所有的方法,并使用了其他帖子/教程中解释的确切方法。我知道您需要使用光标并设置第一个和最后一个可见文档,以便在向前移动的情况下从最后一个文档开始,在向后移动的情况下在第一个文档之前开始。
In my implementation, going forwards works fine. However, when I utilize the previousPage function, it returns me to the first page, despite setting the 'first visible' document. It returns to the first page even if I've already moved 3 'pages' forward.
在我的实现中,向前工作得很好。然而,当我使用previousPage函数时,它会返回到第一页,尽管设置了“第一个可见”文档。它返回到第一页,即使我已经向前移动了3 '页'。
Clearly there is something I'm not understanding here..
很明显,这里有些事情我不明白..
const PAGE_SIZE = 6;
const [posts, setPosts] = useState([]);
const [lastVisible, setLastVisible] = useState(null);
const [firstVisible, setFirstVisible] = useState(null);
const [loading, setLoading] = useState(false);
// Initial read to get first set of posts.
useEffect(() => {
const q = query(
collectionGroup(db, "bulletins"),
orderBy("createdAt", "desc"),
limit(PAGE_SIZE)
);
const unsubscribe = onSnapshot(q, (documents) => {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
setLastVisible(documents.docs[documents.docs.length - 1]);
setFirstVisible(documents.docs[0]);
});
return () => unsubscribe();
}, []);
const nextPage = async () => {
const postsRef = collectionGroup(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
startAfter(lastVisible),
limit(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const previousPage = async () => {
const postsRef = collectionGroup(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
endBefore(firstVisible),
limit(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const updateState = (documents) => {
if (!documents.empty) {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
}
if (documents?.docs[0]) {
setFirstVisible(documents.docs[0]);
}
if (documents?.docs[documents.docs.length - 1]) {
setLastVisible(documents.docs[documents.docs.length - 1]);
}
};
更多回答
优秀答案推荐
You should use endAt()
instead of endBefore()
and also, you should pass the order reference which is the createdAt
to the endAt()
method. See code below:
您应该使用endAt()而不是endBepred(),并且应该将Order引用(即createdAt)传递给endAt()方法。请参阅下面的代码:
const PAGE_SIZE = 6;
const [posts, setPosts] = useState([]);
const [lastVisible, setLastVisible] = useState(null);
const [firstVisible, setFirstVisible] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const q = query(
collectionGroup(db, "bulletins"),
orderBy("createdAt", "desc"),
limit(PAGE_SIZE)
);
const unsubscribe = onSnapshot(q, (documents) => {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
setLastVisible(documents.docs[documents.docs.length - 1]);
setFirstVisible(documents.docs[0]);
});
return () => unsubscribe();
}, []);
const nextPage = async () => {
const postsRef = collectionGroup(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
startAfter(lastVisible.data().createdAt), // Pass the reference
limit(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const previousPage = async () => {
const postsRef = collection(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
endAt(firstVisible.data().createdAt), // Use `endAt()` method and pass the reference
limitToLast(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const updateState = (documents) => {
if (!documents.empty) {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
}
if (documents?.docs[0]) {
setFirstVisible(documents.docs[0]);
}
if (documents?.docs[documents.docs.length - 1]) {
setLastVisible(documents.docs[documents.docs.length - 1]);
}
};
For more information, See Add a simple cursor to a query.
有关详细信息,请参阅向查询添加简单游标。
Here is the updated version of pagination which could be used for Firebase Database + NextJS/React.
以下是可用于Firebase数据库+NextJS/React的分页的更新版本。
Retrieve Data
const PAGE_SIZE = 6;
const [paginatedPosts, setPaginatedPosts] = useState([]);
const [lastVisible, setLastVisible] = useState(null);
const [firstVisible, setFirstVisible] = useState(null);
useEffect(() => {
const q = query(
collectionGroup(database, "posts"),
orderBy("createdAt", "desc"),
limit(PAGE_SIZE)
);
const unsubscribe = onSnapshot(q, (documents) => {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
date: document.data().date,
title: document.data().title,
title_sub: document.data().title_sub,
text: document.data().text,
innerImage: document.data().innerImage,
goBackLink: "/research"
});
});
setPaginatedPosts(tempPosts);
setLastVisible(documents.docs[documents.docs.length - 1]);
setFirstVisible(documents.docs[0]);
});
return () => unsubscribe();
}, []);
const handleNextPage = async () => {
console.log('next page')
const next = query(collectionGroup(database, "posts"),
orderBy("createdAt", "desc"),
startAfter(lastVisible),
limit(PAGE_SIZE));
const documents = await getDocs(next);
updateState(documents);
}
// createdAt
const handlePreviousPage = async () => {
console.log('previous page')
const next = query(collectionGroup(database, "posts"),
orderBy("createdAt", "desc"),
endAt(firstVisible),
limit(PAGE_SIZE));
const documents = await getDocs(next);
updateState(documents);
}
const updateState = (documents) => {
if (!documents.empty) {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
date: document.data().date,
title: document.data().title,
title_sub: document.data().title_sub,
text: document.data().text,
innerImage: document.data().innerImage,
goBackLink: "/research"
});
});
setPaginatedPosts(tempPosts);
}
if (documents?.docs[0]) {
setFirstVisible(documents.docs[0]);
}
if (documents?.docs[documents.docs.length - 1]) {
setLastVisible(documents.docs[documents.docs.length - 1]);
}
};
Render Data with Tailwind
<div className="flex items-center justify-center space-y-4 py-5">
<div className="flex flex-row flex-wrap items-center space-x-2">
<button onClick={handlePreviousPage} className="inline-flex items-center justify-center w-40 h-10 text-md font-poppins font-light text-white bg-t_brown border-none rounded-full no-underline hover:bg-t_brownlight duration-500 whitespace-nowrap">
<svg className="w-3.5 h-3.5 mr-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 5H1m0 0 4 4M1 5l4-4"/>
</svg>
Previous
</button>
<button onClick={handleNextPage} className="inline-flex items-center justify-center w-40 h-10 text-md font-poppins font-light text-white bg-t_brown border-none rounded-full no-underline hover:bg-t_brownlight duration-500 whitespace-nowrap">
Next
<svg className="w-3.5 h-3.5 ml-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M1 5h12m0 0L9 1m4 4L9 9"/>
</svg>
</button>
</div>
</div>
更多回答
我是一名优秀的程序员,十分优秀!