๐Ÿคจ useSWRInfinite ์‚ฌ์šฉ๊ธฐ

๋ฐ•์ƒ์€ยท2022๋…„ 5์›” 2์ผ
0

โœ๏ธ blelog โœ๏ธ

๋ชฉ๋ก ๋ณด๊ธฐ
7/13

ํŠน์ • ๊ฒŒ์‹œ๊ธ€์˜ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ํ•œ ๋ฒˆ์— ๋ชจ๋“  ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๋ณด๋‹จ ์ผ๋ถ€๋ถ„ ๋‚˜๋ˆ ์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ๋” ๋งž๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ useSWRInfinite๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘‡ 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[];
}

๐Ÿ‘‹ UX ํ–ฅ์ƒ์„ ์œ„ํ•œ ์ฝ”๋“œ ์ ์šฉ

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•œ ๋ฐฉ์‹์€ ์ถ”๊ฐ€๋กœ ์š”์ฒญํ•  ๋Œ“๊ธ€์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋ฐฉ์‹์„ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
๋งŒ๋“ค๊ณ  ๋‚˜์„œ ๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋‹ˆ ํ˜„์žฌ ํŽ˜์ด์ง€์˜ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์™€์„œ ์œ ์ €๊ฐ€ ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ ๋” ๋น ๋ฅด๊ฒŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์‹œ๊ฐ€ ์žˆ์–ด์„œ ๊ทธ๊ฒƒ์„ ๋ณด๊ณ  ์กฐ๊ธˆ ๋ณ€ํ˜•ํ•ด์„œ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋ฒ„ํŠผ์— ๋งˆ์šฐ์Šค๊ฐ€ ์˜ฌ๋ผ์™”์„ ๊ฒฝ์šฐ( ํด๋ฆญ ์ด์ „์— ) ๋ฏธ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์น˜ํ•˜๊ณ  ์ดํ›„์— ํด๋ฆญํ•˜๋ฉด ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์„œ ์œ ์ €๊ฐ€ ์กฐ๊ธˆ์ด๋ผ๋„ ๋น ๋ฅด๊ฒŒ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ˜ถ ์ฐธ๊ณ  ๋งํฌ

0๊ฐœ์˜ ๋Œ“๊ธ€