Skip to content

Commit cf7f45b

Browse files
committed
feat: adds infinite scrolling for blogposts
1 parent f0c5a67 commit cf7f45b

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

Diff for: components/uiLibrary/spinner.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
3+
const Spinner: React.FC = () => {
4+
return (
5+
<div
6+
className="inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-current border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]"
7+
role="status">
8+
<span
9+
className="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]">
10+
Loading...
11+
</span>
12+
</div>
13+
);
14+
};
15+
16+
export default Spinner;

Diff for: pages/blog.tsx

+42-12
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,50 @@
11
import {NextPage} from "next";
2-
import {useEffect, useState} from "react";
2+
import {useCallback, useEffect, useRef, useState} from "react";
33
import Post from "../components/blog/post";
44
import {BlogPostsResponse} from "../types/blogPostsResponse";
55
import Head from "next/head";
66
import Container from "../components/uiLibrary/container";
7+
import {BlogPost} from "../types/blogPost";
8+
import Spinner from "../components/uiLibrary/spinner";
79

810

911
const Blog: NextPage = () => {
10-
const [posts, setPosts] = useState({} as BlogPostsResponse);
11-
const [currentPage, setCurrentPage] = useState(1);
12+
const [postsResponse, setPostsResponse] = useState<BlogPostsResponse>();
13+
const [posts, setPosts] = useState<BlogPost[]>([]);
1214
const [loading, setLoading] = useState(true);
15+
const INITIAL_PAGE = "https://changelog.unitystation.org/posts/?page=1";
16+
17+
const fetchPosts = async (url: string) : Promise<BlogPostsResponse> => {
18+
setLoading(true);
19+
const response = await fetch(url);
20+
return await response.json();
21+
};
22+
23+
useEffect(() => {
24+
fetchPosts(INITIAL_PAGE)
25+
.then(json => {
26+
setPostsResponse(json);
27+
setPosts(json.results);
28+
})
29+
.finally(() => setLoading(false));
30+
}, []);
31+
32+
const handleScroll = useCallback(async () => {
33+
if (window.innerHeight + document.documentElement.scrollTop !== document.documentElement.offsetHeight || !postsResponse?.next) return;
34+
setLoading(true);
35+
36+
const json = await fetchPosts(postsResponse.next);
37+
38+
setPosts((prevPosts) => [...prevPosts, ...json.results]);
39+
setPostsResponse(json);
40+
41+
setLoading(false);
42+
}, [postsResponse]);
1343

1444
useEffect(() => {
15-
fetch(`https://changelog.unitystation.org/posts`)
16-
.then(response => response.json())
17-
.then(json => setPosts(json))
18-
.then(() => setLoading(false))
19-
}, [currentPage]);
45+
window.addEventListener('scroll', handleScroll);
46+
return () => window.removeEventListener('scroll', handleScroll);
47+
}, [handleScroll]);
2048

2149
return (
2250
<>
@@ -39,8 +67,9 @@ const Blog: NextPage = () => {
3967
/>
4068
</Head>
4169
<Container>
42-
{!loading && <div>
43-
{posts.results.map((post) => {
70+
<ul id="posts">
71+
{posts &&
72+
posts.map((post) => {
4473
return (
4574
<Post
4675
key={post.slug}
@@ -52,9 +81,10 @@ const Blog: NextPage = () => {
5281
state={post.state}
5382
type={post.type}
5483
/>
55-
)
84+
);
5685
})}
57-
</div>}
86+
</ul>
87+
{loading && <Spinner/>}
5888
</Container>
5989
</>
6090
)

0 commit comments

Comments
 (0)