-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 스레드 조회 API 작성 * feat: 스레드 조회 msw 작성 * feat: 스레드 조회 API 작성 * feat: 스레드 조회 msw 작성 * refactor: handlers에 feed handler 추가 * refactor: searchParams last-thread-id로 변경 * fix: 스레드 조회 msw 19개씩 가져오는 문제 fix * feat: 스레드 조회 getNextPageParam 구현 * feat: 스레드 마지막 관찰하는 intersection 훅 구현 * feat: 스레드 리스트 구현 * feat: 스레드 리스트 스토리 구현 * refactor: ThreadData 네이밍 변경 * refactor: 의존성 배열 추가 * refactor: MutableRefObject사용해여 IntersectionObserver 구현
- Loading branch information
1 parent
424523d
commit 967ed35
Showing
11 changed files
with
973 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { http } from '~/apis/http'; | ||
import { THREAD_SIZE } from '~/constants/feed'; | ||
import type { Thread } from '~/types/feed'; | ||
|
||
export const fetchThreads = (teamPlaceId: number, lastThreadId?: number) => { | ||
const query = lastThreadId | ||
? `last-thread-id=${lastThreadId}&size=${THREAD_SIZE}` | ||
: `size=${THREAD_SIZE}`; | ||
|
||
return http.get<{ | ||
threads: Thread[]; | ||
}>(`/api/team-place/${teamPlaceId}/feed/threads?${query}`); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import ThreadList from '~/components/ThreadList/ThreadList'; | ||
|
||
const meta = { | ||
title: 'Feed/ThreadList', | ||
component: ThreadList, | ||
tags: ['autodocs'], | ||
} satisfies Meta<typeof ThreadList>; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: {}, | ||
}; | ||
|
||
export const Small: Story = { | ||
args: { size: 'sm' }, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { css, styled } from 'styled-components'; | ||
|
||
export const Container = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
overflow: auto; | ||
width: 100%; | ||
max-height: 700px; | ||
height: auto; | ||
gap: 30px; | ||
`; | ||
|
||
export const lastThreadText = css` | ||
display: flex; | ||
align-self: center; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { useFetchThreads } from '~/hooks/queries/useFetchThreads'; | ||
import * as S from './ThreadList.styled'; | ||
import type { ThreadSize } from '~/types/size'; | ||
import { THREAD_TYPE } from '~/constants/feed'; | ||
import Thread from '~/components/Thread/Thread'; | ||
import Notification from '~/components/Notification/Notification'; | ||
import { useRef } from 'react'; | ||
import { useIntersectionObserver } from '~/hooks/useIntersectionObserver'; | ||
import Text from '~/components/common/Text/Text'; | ||
|
||
interface ThreadListProps { | ||
size?: ThreadSize; | ||
} | ||
|
||
const ThreadList = (props: ThreadListProps) => { | ||
const { size = 'md' } = props; | ||
const { threadPages, hasNextPage, fetchNextPage } = useFetchThreads(1); | ||
const observeRef = useRef<HTMLDivElement>(null); | ||
|
||
const onIntersect: IntersectionObserverCallback = ([entry]) => | ||
entry.isIntersecting && fetchNextPage(); | ||
|
||
useIntersectionObserver(observeRef, onIntersect); | ||
|
||
return ( | ||
<S.Container> | ||
{threadPages?.pages.map((page) => | ||
page.threads.map((thread) => { | ||
const { id, type, profileImageUrl, content, ...rest } = thread; | ||
const profileUrl = profileImageUrl === null ? '' : profileImageUrl; | ||
|
||
return type === THREAD_TYPE.THREAD ? ( | ||
<Thread | ||
key={id} | ||
size={size} | ||
profileImageUrl={profileUrl} | ||
content={content} | ||
{...rest} | ||
/> | ||
) : ( | ||
<Notification key={id} size={size} content={content} /> | ||
); | ||
}), | ||
)} | ||
{!hasNextPage && ( | ||
<Text size="lg" weight="bold" css={S.lastThreadText}> | ||
마지막 스레드 입니다. | ||
</Text> | ||
)} | ||
<div ref={observeRef} /> | ||
</S.Container> | ||
); | ||
}; | ||
|
||
export default ThreadList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export const THREAD_TYPE = { | ||
THREAD: 'thread', | ||
NOTIFICATION: 'notification', | ||
}; | ||
|
||
export const THREAD_SIZE = 20; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { useInfiniteQuery } from '@tanstack/react-query'; | ||
import { fetchThreads } from '~/apis/feed'; | ||
import { THREAD_SIZE } from '~/constants/feed'; | ||
|
||
export const useFetchThreads = (teamPlaceId: number) => { | ||
const { | ||
data: threadPages, | ||
hasNextPage, | ||
fetchNextPage, | ||
} = useInfiniteQuery( | ||
['threadData', teamPlaceId], | ||
({ pageParam = undefined }) => fetchThreads(teamPlaceId, pageParam), | ||
{ | ||
getNextPageParam: (lastPage) => { | ||
if (lastPage.threads.length !== THREAD_SIZE) return undefined; | ||
return lastPage.threads[THREAD_SIZE - 1].id; | ||
}, | ||
}, | ||
); | ||
|
||
return { threadPages, hasNextPage, fetchNextPage }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { useEffect, type RefObject, useRef } from 'react'; | ||
|
||
export const useIntersectionObserver = <T extends HTMLElement>( | ||
targetRef: RefObject<T>, | ||
onIntersect: IntersectionObserverCallback, | ||
) => { | ||
const observer = useRef<IntersectionObserver>(); | ||
useEffect(() => { | ||
if (targetRef && targetRef.current) { | ||
observer.current = new IntersectionObserver(onIntersect, { | ||
root: null, | ||
rootMargin: '0px', | ||
threshold: 1.0, | ||
}); | ||
|
||
observer.current.observe(targetRef.current); | ||
} | ||
|
||
return () => observer && observer.current?.disconnect(); | ||
}, [targetRef, onIntersect]); | ||
}; |
Oops, something went wrong.