Skip to content

Commit

Permalink
Merge pull request #90 from kakao-tech-campus-2nd-step3/feat/#82-disc…
Browse files Browse the repository at this point in the history
…over

둘러보기(discover) 페이지 구현 #82
  • Loading branch information
joojjang authored Nov 9, 2024
2 parents 5f0955a + 58320aa commit 3daf3e9
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
51 changes: 51 additions & 0 deletions src/apis/products/useGetFeed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useSuspenseInfiniteQuery } from '@tanstack/react-query';
import { isAxiosError } from 'axios';

import { fetchInstance } from '../instance';

export type Product = {
id: number;
name: string;
artist: string;
price: number;
thumbnailUrl: string;
};

type GetFeedResponse = {
hasNext: boolean;
products: Product[];
};

async function getFeed(size: number, pageParam: number): Promise<GetFeedResponse> {
try {
const response = await fetchInstance().get(`/products/feed?size=${size}&page=${pageParam}`);
// console.log('getFeed response: ', response);

return response.data;
} catch (error) {
if (isAxiosError(error)) {
if (error.response) {
throw new Error(error.response.data.message || '피드 가져오기 실패');
} else {
throw new Error('네트워크 오류 또는 서버에 연결할 수 없습니다.');
}
} else {
throw new Error('알 수 없는 오류입니다.');
}
}
}

const useGetFeed = () => {
const size = 20;

return useSuspenseInfiniteQuery<GetFeedResponse, Error, void>({
queryKey: ['feed', size],
queryFn: ({ pageParam = 0 }) => getFeed(size, pageParam as number),
initialPageParam: 0,
getNextPageParam: (lastPage) => {
return lastPage.hasNext ? lastPage.products.length / size + 1 : undefined;
},
});
};

export default useGetFeed;
5 changes: 4 additions & 1 deletion src/components/layouts/SearchBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import CancelIcon from '@/assets/icons/cancel-filled-gray.svg?react';
import SearchIcon from '@/assets/icons/search.svg?react';
import IconButton from '@/components/common/IconButton';
import { SEARCH_ARRAY_KEY } from '@/components/common/SearchModal/RecentSearch';
import Z_INDEX from '@/styles/z_index';
import { useForm } from 'react-hook-form';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { HEADER_HEIGHT } from '../Header';
Expand Down Expand Up @@ -88,7 +89,8 @@ export default SearchBar;
const SEARCHBAR_HEIGHT = HEADER_HEIGHT;

const SearchBarWrapper = styled.div`
position: sticky;
position: fixed;
z-index: ${Z_INDEX.Header};
top: 0;
width: 100%;
height: ${SEARCHBAR_HEIGHT};
Expand All @@ -97,6 +99,7 @@ const SearchBarWrapper = styled.div`
justify-content: space-between;
align-items: center;
gap: 10px;
background-color: var(--color-white);
`;

const InputBox = styled.form`
Expand Down
73 changes: 72 additions & 1 deletion src/pages/Discover/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,76 @@
import styled from '@emotion/styled';
import { Suspense, useEffect } from 'react';

import useGetFeed, { type Product } from '@/apis/products/useGetFeed';
import { HEADER_HEIGHT } from '@/components/layouts/Header';
import SearchBar from '@/components/layouts/SearchBar';
import { TABBAR_HEIGHT } from '@/components/layouts/TabBar';

const Discover = () => {
return <>Discover</>;
const { data, fetchNextPage, hasNextPage } = useGetFeed();

// 스크롤 내려감에 따라 다음 페이지 데이터 페칭
const handleScroll = () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 100 && hasNextPage) {
fetchNextPage();
}
};

useEffect(() => {
window.addEventListener('scroll', handleScroll);

return () => window.removeEventListener('scroll', handleScroll); // 언마운트될 때 이벤트 리스너 해제
}, [fetchNextPage, hasNextPage]);

return (
<Wrapper>
<SearchBar />
<ContentWrapper>
<Suspense fallback={<>Loading...</>}>
<ImageGrid>
{data?.pages.map((page) =>

Check failure on line 32 in src/pages/Discover/index.tsx

View workflow job for this annotation

GitHub Actions / Deploy

Property 'pages' does not exist on type 'never'.

Check failure on line 32 in src/pages/Discover/index.tsx

View workflow job for this annotation

GitHub Actions / Deploy

Parameter 'page' implicitly has an 'any' type.
page.products.map((product: Product) => (
<ImageItem key={product.id}>
<img src={product.thumbnailUrl} alt={product.name} />
</ImageItem>
)),
)}
</ImageGrid>
</Suspense>
</ContentWrapper>
</Wrapper>
);
};

export default Discover;

const Wrapper = styled.div`
flex: 1;
display: flex;
flex-direction: column;
margin: ${HEADER_HEIGHT} 0 ${TABBAR_HEIGHT} 0;
`;

const ContentWrapper = styled.div`
padding: 4px;
overflow-y: auto;
flex: 1;
`;

const ImageGrid = styled.div`
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 8px;
`;

const ImageItem = styled.div`
border-radius: var(--border-radius);
overflow: hidden;
img {
width: 100%;
height: auto;
display: block;
}
`;

0 comments on commit 3daf3e9

Please sign in to comment.