ํน์ ๊ฒ์๊ธ์ ๋๊ธ์ ๊ฐ์ ธ์ฌ ๋ ํ ๋ฒ์ ๋ชจ๋ ๋๊ธ์ ๊ฐ์ ธ์ค๋ ๊ฒ๋ณด๋จ ์ผ๋ถ๋ถ ๋๋ ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ๋ ๋ง๋ค๊ณ ์๊ฐํ์ฌ
useSWRInfinite
๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
import useSWRInfinite from 'swr/infinite'
// getKey ์ฌ์ฉ ํํ
// ํ์ฌ ํ์ด์ง + 1๊ณผ ์ด์ ํ์ด์ง์ ๋ํ ์ ๋ณด๋ฅผ ๋ฐํ
const getKey = (pageIndex, previousPageData) => {
// ์ด์ ํ์ด์ง์ ์ ๋ณด๋ฅผ ์ด์ฉํด์ ๋ ๋ถ๋ฌ์จ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด null์ ๋ฐํํด์ ์ถ๊ฐ์ ์ผ๋ก ์์ฒญ์ ํด๋ ๋ ์ด์ ๋ฐ์ ๋ฐ์ดํฐ๊ฐ ์์์ ๋ช
์
if (previousPageData && !previousPageData.length) return null // ๋์ ๋๋ฌ
// ๋ ๋ฐ์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๋ค๋ฉด ์์ฒญํ url์ ๋ฐํํจ
return `/users?page=${pageIndex}&limit=10`
};
// ...
// fetcher๋ useSWR()๊ณผ ๋์ผํ๊ณ , option์ ๊ธฐ์กด๊ฐ + ์ถ๊ฐ 4๊ฐ์ ๊ฐ์ด ๋ ์กด์ฌํจ ( ์์ธํ๊ฑด ๊ณต์๋ฌธ์ ์ฐธ๊ณ )
const { data, error, isValidating, mutate, size, setSize } = useSWRInfinite<ResponseType>(
getKey, fetcher?, options?
);
// === data์ ๋ฐํ ํํ ===
// ๋ฐํ ํํ๊ฐ useSWR()๊ณผ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ๊ฑฐ๋ mutate()๋ฅผ ์ด์ฉํ ๋ ์ธ์งํ๊ณ ์ฌ์ฉํด์ผ ํ์
์ค๋ฅ ์์ด ์ฌ์ฉํ ์ ์๋ค.
// useSWR()์ ๊ทธ๋ฅ ResponseType ํํ๋ก ๋ฐํํ๊ณ
// useSWRInfinite()๋ ์ด์ฐจ์ ๋ฐฐ์ด ๋ด๋ถ์ ResponseType์ด ๋ค์ด๊ฐ ์๋ ํํ๋ค.
[
[
// ResponseType ํํ
],
[
// ResponseType ํํ
],
// ...
]
// 2022/05/02 - ๋๊ธ offset - by 1-blue
const [offset, setOffset] = useState(10);
// 2022/05/02 - ๋๊ธ ์ถ๊ฐ ํจ์น ๊ฐ๋ฅ ์ฌ๋ถ - by 1-blue
const [hasMoreComment, setHasMoreComment] = useState(true);
// 2022/05/02 - ๋๊ธ๋ค ์์ฐจ์ ์์ฒญ - by 1-blue
const {
data: commentsResponse,
setSize,
mutate: commentsMutate,
isValidating: commentsLoading,
} = useSWRInfinite<CommentsResponse>(
router.query.title
? (pageIndex, previousPageData) => {
// ์ด ๋ถ๋ถ์ ์ถ๊ฐ๋ก ์์ฑํ ์ด์ ๋ ๋ฐ์์ค๋ ๋ฐ์ดํฐ๊ฐ offset์ ๊ฐ์ ์ดํ๋ผ๋ฉด ๋น์ฐํ ์ถ๊ฐ์ ์ผ๋ก ๋ฐ์์ฌ ๋ฐ์ดํฐ๊ฐ ์๋ค๊ณ ํ๋จํด์ ์ถ๊ฐํจ
// 10๊ฐ์ฉ ๋ฐ์์ค๋ค๊ฐ 6๊ฐ๋ฅผ ๋ฐ์์๋ค๋ฉด ๋น์ฐํ ๊ทธ ๋ค์ ๋ฐ์์ฌ ๋ฐ์ดํฐ๋ ์์ด์ ์ต๋ํ ์ถ๊ฐ์ ์ธ ์์ฒญ์ ํ์ง ์๊ฒ ํจ
if (previousPageData && previousPageData.comments.length !== offset) {
setHasMoreComment(false);
return null;
}
if (previousPageData && !previousPageData.comments.length) {
setHasMoreComment(false);
return null;
}
return `/api/post/${router.query.title}/comment?page=${pageIndex}&offset=${offset}`;
}
: () => null
);
// ๋๊ธ ์ถ๊ฐ mutate() ์ฌ์ฉ
commentsMutate(
(prev) =>
prev && [
{
ok: true,
comments: [
{
idx: Date.now(),
contents: body.comment,
postIdx: postIdx,
createdAt: new Date(Date.now()),
updatedAt: new Date(Date.now()),
user: me!,
commentIdx: undefined,
},
],
},
...prev,
],
false
);
// ๋๊ธ ์ญ์ mutate() ์ฌ์ฉ
commentsMutate(
(prev) =>
prev &&
prev.map(({ comments }) => ({
ok: true,
comments: comments.filter((comment) => comment.idx !== commentIdx),
})),
false
);
// ๋๊ธ ํ์
type Comment = {
idx: number;
contents: string;
createdAt: Date;
updatedAt: Date;
postIdx: number;
commentIdx?: number;
};
interface ICommentWithUser extends Comment {
user: {
id: number;
name: string;
avatar: string;
introduction?: string;
}
}
type CommentsResponse = {
ok: boolean;
comments: ICommentWithUser[];
}
ํ์ฌ ํ๋ก์ ํธ์ ์ ์ฉํ ๋ฐฉ์์ ์ถ๊ฐ๋ก ์์ฒญํ ๋๊ธ์ด ์๋ ๊ฒฝ์ฐ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๋ฐฉ์์ ์ ์ฉํ์ต๋๋ค.
๋ง๋ค๊ณ ๋์ ๊ณต์๋ฌธ์๋ฅผ ๋ณด๋ ํ์ฌ ํ์ด์ง์ ๋ค์ ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์ ธ์์ ์ ์ ๊ฐ ๋ค์ ํ์ด์ง๋ก ๋์ด๊ฐ ๋ ๋ ๋น ๋ฅด๊ฒ ์ด๋ํ ์ ์๋๋ก ๊ตฌํํ๋ ์์๊ฐ ์์ด์ ๊ทธ๊ฒ์ ๋ณด๊ณ ์กฐ๊ธ ๋ณํํด์ ์ ์ฉํ์ต๋๋ค.
๋ง์ฝ ๋ฒํผ์ ๋ง์ฐ์ค๊ฐ ์ฌ๋ผ์์ ๊ฒฝ์ฐ( ํด๋ฆญ ์ด์ ์ ) ๋ฏธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํจ์นํ๊ณ ์ดํ์ ํด๋ฆญํ๋ฉด ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ก ๋ณด์ฌ์ฃผ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ ์ ์ ๊ฐ ์กฐ๊ธ์ด๋ผ๋ ๋น ๋ฅด๊ฒ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๊ตฌํํ์ต๋๋ค.