Skip to content

Commit

Permalink
🎉 각 리스트 ErrorBoundary, Suspense 적용 (#145)
Browse files Browse the repository at this point in the history
* 🎉 각 리스트 ErrorBoundary, Suspense 적용

* 🎉 NoData UI 버그 해결
- 탭과 isEmpty fallback 이 겹치는 현상 해결
  • Loading branch information
doggopawer authored Dec 1, 2023
1 parent c93af22 commit 9e73992
Show file tree
Hide file tree
Showing 24 changed files with 507 additions and 460 deletions.
Original file line number Diff line number Diff line change
@@ -1,65 +1,25 @@
'use client'

import { useEffect, useRef } from 'react'
import { Suspense } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { useSearchParams } from 'next/navigation'
import ExceptionBoundary from '@/components/domain/exception-boundary'
import { useCardsQuery } from '@/hooks/api/queries/useCardsQuery'
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'
import { CategoryObjs, PriceRangeObjs } from '@/types/card'
import Loading from '@/app/loading'
import DefaultErrorTemplate from '@/components/domain/errors/DefaultErrorTemplate'
import CardFilterSection from '../card-filter-section'
import CardList from '../card-list/CardList'

const CardListContent = () => {
const searchParams = useSearchParams()

// TODO: 현재 API 명세에 status에 어떤 값을 줘야하는지에 대한 정의가 되어 있지 않기 때문에 임시로 상수 값을 전달함 => 추후에 실제 동작 값으로 고치기
const {
data,
fetchNextPage,
isError,
isFetchingNextPage,
isLoading,
hasNextPage,
} = useCardsQuery({
category:
(searchParams.get('category') as CategoryObjs['key']) || undefined,
priceRange:
(searchParams.get('priceRange') as PriceRangeObjs['key']) || undefined,
cardTitle: searchParams.get('cardTitle' as string) || '',
})

const lastElementRef = useRef<HTMLDivElement | null>(null)
const entry = useIntersectionObserver(lastElementRef, { threshold: 1.0 })

useEffect(() => {
if (isFetchingNextPage || !hasNextPage) {
return
}

if (entry?.isIntersecting) {
fetchNextPage()
}
}, [entry?.isIntersecting, fetchNextPage, isFetchingNextPage, hasNextPage])

// TODO: 아이템이 없을시 어떤 UI를 보여줄지 차후에 결정

const isEmpty = data?.pages[0].data.cardList.length === 0

return (
<>
<CardFilterSection />
<ExceptionBoundary
isLoading={isLoading}
isError={isError}
isEmpty={isEmpty}
isFetchingNextPage={isFetchingNextPage}
<ErrorBoundary
fallback={
<DefaultErrorTemplate onClickButton={() => console.log('재시도')} />
}
>
<ErrorBoundary fallback={<div>렌더링 중 문제가 발생했습니다.</div>}>
<Suspense fallback={<Loading />}>
<CardList />
</ErrorBoundary>
</ExceptionBoundary>
<div ref={lastElementRef} />
</Suspense>
</ErrorBoundary>
</>
)
}
Expand Down
54 changes: 43 additions & 11 deletions src/app/(root)/(routes)/cards/components/card-list/CardList.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
import { Fragment } from 'react'
import { useSearchParams } from 'next/navigation'
import { Fragment, useEffect, useRef } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import TradeStatusCard from '@/components/domain/card/trade-status-card'
import EmptyDataWrapper from '@/components/domain/empty-data-wrapper'
import NoData from '@/components/domain/no-data'
import AppPath from '@/config/appPath'
import { useCardsQuery } from '@/hooks/api/queries/useCardsQuery'
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'
import { GetCardListRes } from '@/services/card/card'
import { Card, CategoryObjs, PriceRangeObjs } from '@/types/card'

const CardList = () => {
const searchParams = useSearchParams()
const router = useRouter()

const { data } = useCardsQuery({
category:
(searchParams.get('category') as CategoryObjs['key']) || undefined,
priceRange:
(searchParams.get('priceRange') as PriceRangeObjs['key']) || undefined,
cardTitle: searchParams.get('cardTitle' as string) || '',
})
// TODO: 현재 API 명세에 status에 어떤 값을 줘야하는지에 대한 정의가 되어 있지 않기 때문에 임시로 상수 값을 전달함 => 추후에 실제 동작 값으로 고치기
const { data, fetchNextPage, isFetchingNextPage, hasNextPage } =
useCardsQuery({
category:
(searchParams.get('category') as CategoryObjs['key']) || undefined,
priceRange:
(searchParams.get('priceRange') as PriceRangeObjs['key']) || undefined,
cardTitle: searchParams.get('cardTitle' as string) || '',
})

const lastElementRef = useRef<HTMLDivElement | null>(null)
const entry = useIntersectionObserver(lastElementRef, { threshold: 1.0 })

useEffect(() => {
if (isFetchingNextPage || !hasNextPage) {
return
}

if (entry?.isIntersecting) {
fetchNextPage()
}
}, [entry?.isIntersecting, fetchNextPage, isFetchingNextPage, hasNextPage])

const isEmpty = data?.pages[0].data.cardList.length === 0

return (
<>
<EmptyDataWrapper
isEmpty={isEmpty}
fallback={
<NoData
title={'해당 물건이 없습니다.'}
buttonContent={'물건 등록하기'}
onClickButton={() => router.push(AppPath.newCard())}
/>
}
>
{data?.pages.map(({ data: { cardList } }: GetCardListRes, pageIndex) => (
<Fragment key={pageIndex}>
{cardList.map((card: Card) => (
Expand All @@ -27,7 +58,8 @@ const CardList = () => {
))}
</Fragment>
))}
</>
<div ref={lastElementRef} />
</EmptyDataWrapper>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,31 @@
'use client'

import { useEffect, useRef, useState } from 'react'
import { Suspense, useState } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import ExceptionBoundary from '@/components/domain/exception-boundary'
import { useMyCardsQuery } from '@/hooks/api/queries/useMyCardsQuery'
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'
import Loading from '@/app/loading'
import DefaultErrorTemplate from '@/components/domain/errors/DefaultErrorTemplate'
import { TradeStatus } from '@/types/card'
import MyCardList from '../my-card-list/MyCardList'
import TradeStatusTabs from '../trade-status-tabs'

const MyCardListContent = () => {
const [tradeStatus, setTradeStatus] = useState<TradeStatus>('TRADE_AVAILABLE')

const {
data,
fetchNextPage,
isLoading,
isError,
isFetchingNextPage,
hasNextPage,
} = useMyCardsQuery({
tradeStatus,
})

const lastElementRef = useRef<HTMLDivElement | null>(null)
const entry = useIntersectionObserver(lastElementRef, { threshold: 1.0 })

useEffect(() => {
if (isFetchingNextPage || !hasNextPage) {
return
}

if (entry?.isIntersecting) {
fetchNextPage()
}
}, [entry?.isIntersecting, fetchNextPage, isFetchingNextPage, hasNextPage])

const isEmpty = data?.pages[0].data.cardList.length === 0
return (
<>
<TradeStatusTabs
tradeStatus={tradeStatus}
setTradeStatus={setTradeStatus}
/>
<ExceptionBoundary
isLoading={isLoading}
isError={isError}
isEmpty={isEmpty}
isFetchingNextPage={isFetchingNextPage}
<ErrorBoundary
fallback={
<DefaultErrorTemplate onClickButton={() => console.log('재시도')} />
}
>
<ErrorBoundary fallback={<div>렌더링 중 문제가 발생했습니다.</div>}>
<MyCardList data={data} />
</ErrorBoundary>
</ExceptionBoundary>

<div ref={lastElementRef} />
<Suspense fallback={<Loading />}>
<MyCardList tradeStatus={tradeStatus} />
</Suspense>
</ErrorBoundary>
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,48 @@
import { Fragment } from 'react'
import { InfiniteData } from '@tanstack/react-query'
import { Fragment, useEffect, useRef } from 'react'
import { useRouter } from 'next/navigation'
import EmptyDataWrapper from '@/components/domain/empty-data-wrapper/EmptyDataWrapper'
import NoData from '@/components/domain/no-data'
import AppPath from '@/config/appPath'
import { useMyCardsQuery } from '@/hooks/api/queries/useMyCardsQuery'
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'
import { GetMyCardListRes } from '@/services/card/card'
import { Card } from '@/types/card'
import MyCard from '../my-card'

const MyCardList = ({
data,
}: {
data: InfiniteData<GetMyCardListRes, unknown> | undefined
}) => {
const MyCardList = ({ tradeStatus }: { tradeStatus: any }) => {
const router = useRouter()
const { data, fetchNextPage, isFetchingNextPage, hasNextPage } =
useMyCardsQuery({
tradeStatus,
})

const lastElementRef = useRef<HTMLDivElement | null>(null)
const entry = useIntersectionObserver(lastElementRef, { threshold: 1.0 })

useEffect(() => {
if (isFetchingNextPage || !hasNextPage) {
return
}

if (entry?.isIntersecting) {
fetchNextPage()
}
}, [entry?.isIntersecting, fetchNextPage, isFetchingNextPage, hasNextPage])
const isEmpty = data?.pages[0].data.cardList.length === 0
return (
<>
<EmptyDataWrapper
isEmpty={isEmpty}
fallback={
tradeStatus === 'TRADE_AVAILABLE' && (
<NoData
title={'내 물건이 없습니다.'}
buttonContent={'물건 등록하기'}
onClickButton={() => router.push(AppPath.newCard())}
position={false}
/>
)
}
>
{data?.pages.map(
({ data: { cardList } }: GetMyCardListRes, pageIndex) => (
<Fragment key={pageIndex}>
Expand All @@ -20,7 +52,8 @@ const MyCardList = ({
</Fragment>
),
)}
</>
<div ref={lastElementRef} />
</EmptyDataWrapper>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,23 @@
'use client'

import { useEffect, useRef, Fragment } from 'react'
import { Suspense } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import ExceptionBoundary from '@/components/domain/exception-boundary'
import { useChatRoomsQuery } from '@/hooks/api/queries/useChatRoomsQuery'
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'
import Loading from '@/app/loading'
import DefaultErrorTemplate from '@/components/domain/errors/DefaultErrorTemplate'
import ChatRoomList from '../chat-room-list'

const ChatRoomListContent = () => {
const {
data,
fetchNextPage,
isLoading,
isError,
isFetchingNextPage,
hasNextPage,
} = useChatRoomsQuery()

const lastElementRef = useRef<HTMLDivElement | null>(null)
const entry = useIntersectionObserver(lastElementRef, { threshold: 1.0 })

useEffect(() => {
if (isFetchingNextPage || !hasNextPage) {
return
}

if (entry?.isIntersecting) {
fetchNextPage()
}
}, [entry?.isIntersecting, fetchNextPage, isFetchingNextPage, hasNextPage])

const isEmpty = data?.pages[0].data.chatRoomList.length === 0

return (
<>
<ExceptionBoundary
isLoading={isLoading}
isError={isError}
isEmpty={isEmpty}
isFetchingNextPage={isFetchingNextPage}
<ErrorBoundary
fallback={
<DefaultErrorTemplate onClickButton={() => console.log('재시도')} />
}
>
<ErrorBoundary fallback={<div>렌더링 중 문제가 발생했습니다.</div>}>
<ChatRoomList data={data} />
</ErrorBoundary>
</ExceptionBoundary>

<div ref={lastElementRef} />
<Suspense fallback={<Loading />}>
<ChatRoomList />
</Suspense>
</ErrorBoundary>
</>
)
}
Expand Down
Loading

0 comments on commit 9e73992

Please sign in to comment.