Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[정성현] sprint10 #129

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions public/icons/medal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 18 additions & 15 deletions src/components/pages/boards/BestItems.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import { useMediaQuery } from "@/hooks/useMediaQuery";
import { useMedia } from "@/hooks/useMedia";
import { getArticles } from "@/apis/apis";
import { GetArticlesParams, GetArticlesRes } from "@/apis/apis.type";
import { useQuery } from "@/hooks/useQuery";
Expand All @@ -9,33 +9,36 @@ import styles from "./BestItems.module.css";
const pageSizeTable = { PC: 3, TABLET: 2, MOBILE: 1 };

export default function BestItems() {
const media = useMediaQuery();
const [paramObj, setParamObj] = useState<GetArticlesParams>({
page: 1,
pageSize: pageSizeTable[media],
orderBy: "like",
});
const { isLoading, error, data } = useQuery<
const media = useMedia();
const [paramObj, setParamObj] = useState<GetArticlesParams>();
const { isLoading, error, data, query } = useQuery<
GetArticlesParams,
GetArticlesRes
>(getArticles, paramObj);
>(getArticles);

useEffect(() => {
setParamObj((prevObj) => ({
...prevObj,
pageSize: pageSizeTable[media],
}));
if (!media) return;
setParamObj((prevObj) =>
!prevObj
? { page: 1, pageSize: pageSizeTable[media], orderBy: "like" }
: { ...prevObj, pageSize: pageSizeTable[media] }
);
}, [media]);

useEffect(() => {
if (!paramObj) return;
query(paramObj);
}, [query, paramObj]);

return (
<section className={styles.section}>
<div className={styles.head}>
<h2 className={styles.title}>베스트 게시글</h2>
</div>
{!isLoading && !error && data && (
<div className={styles.body}>
{data.list.map((item) => (
<BestItem key={item.id} data={item} />
{data.list.map((article) => (
<BestItem key={article.id} article={article} />
))}
</div>
)}
Expand Down
54 changes: 44 additions & 10 deletions src/components/pages/boards/componnets/BestItem.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,39 @@
display: flex;
flex-direction: column;
gap: 16px;
padding: 0 24px 16px;
border-radius: 8px;
background-color: var(--gray-50);
}

.tag {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
width: 100px;
height: 30px;
border-radius: 0 0 15px 15px;
background-color: var(--blue-100);
font-size: var(--size-lg);
font-weight: var(--semibold);
color: white;
}

.content {
display: flex;
align-items: center;
justify-content: space-between;
}

.title {
font-size: var(--size-xl);
font-weight: var(--semibold);
}
@media (max-width: 1199px) {
.title {
font-size: var(--size-2gl);
}
}

.imageWrapper {
Expand All @@ -16,29 +49,30 @@
object-fit: contain;
}

.content {
.info {
display: flex;
flex-direction: column;
gap: 6px;
}

.title {
align-items: center;
gap: 8px;
font-size: var(--size-md);
}

.price {
font-size: var(--size-lg);
font-weight: bold;
.nickname {
color: var(--gray-600);
}

.like {
flex-grow: 1;
display: flex;
align-items: center;
gap: 4px;
font-size: var(--size-xs);
color: var(--gray-500);
}

.likeIcon {
width: 16px;
height: 16px;
}

.date {
color: var(--gray-400);
}
50 changes: 27 additions & 23 deletions src/components/pages/boards/componnets/BestItem.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
import Link from "next/link";
import Image from "next/image";
import { ArticleProps } from "@/apis/apis.type";
import medalIcon from "#/icons/medal.svg";
import heartIcon from "#/icons/heart_inactive.svg";
import styles from "./BestItem.module.css";
import { ArticleProps } from "@/apis/apis.type";

interface ItemProps {
data: ArticleProps;
article: ArticleProps;
}

export default function BestItem({ data }: ItemProps) {
const {
id,
title,
writer: { nickname },
updatedAt,
image,
likeCount,
} = data;
export default function BestItem({ article }: ItemProps) {
const date = new Date(article.updatedAt).toLocaleDateString();

return (
<Link className={styles.item} href={`/board/${id}`}>
<div className={styles.imageWrapper}>
<Image
className={styles.image}
src={image ? image : ""}
alt={"이미지"}
fill
/>
<Link className={styles.item} href={`/board/${article.id}`}>
<div className={styles.tag}>
<Image src={medalIcon} alt="" />
Best
</div>
<div className={styles.content}>
<span className={styles.title}>{title}</span>
<span className={styles.price}>{updatedAt}</span>
<h3 className={styles.title}>{article.title}</h3>
<div className={styles.imageWrapper}>
{article.image ? (
<Image
className={styles.image}
src={article.image}
alt={"이미지"}
fill
/>
) : undefined}
</div>
</div>
<div className={styles.info}>
<span className={styles.nickname}>{article.writer.nickname}</span>
<div className={styles.like}>
<Image className={styles.likeIcon} src={heartIcon} alt="좋아요 수" />
<span>{likeCount}</span>
<Image className={styles.likeIcon} src={heartIcon} alt="" />
{article.likeCount}
</div>
<span className={styles.date}>{date}</span>
</div>
</Link>
);
Expand Down
7 changes: 7 additions & 0 deletions src/hooks/useMedia.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2:
이건 분리하기보다 mediaContext 파일 하단에 같이 있는게 더 좋을 것 같아요.
이렇게 작업하기 위해서는 결국 mediaContext를 export 하게되서 구지 useMedia 라는 커스텀훅을 이용해서 접근하지 않을 수 있으니까요~

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context 관련해서 아래 블로그 글 한번 읽어보세요~
https://velog.io/@velopert/react-context-tutorial

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useContext } from "react";
import { MediaContext } from "@/store/MediaContext";

export function useMedia() {
const media = useContext(MediaContext);
return media;
}
28 changes: 0 additions & 28 deletions src/hooks/useMediaQuery.ts

This file was deleted.

15 changes: 4 additions & 11 deletions src/hooks/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useState, useCallback, useEffect } from "react";
import { useState, useCallback } from "react";

export function useQuery<Params extends object, Response extends object>(
fetchFunc: (paramObj: Params) => Promise<Response>,
paramObj: Params
fetchFunc: (paramObj: Params) => Promise<Response>
) {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<Error | null>(null);
const [data, setData] = useState<Response | null>(null);

const wrappedFunc = useCallback(
const query = useCallback(
async (paramObj: Params) => {
try {
setIsLoading(true);
Expand All @@ -27,11 +26,5 @@ export function useQuery<Params extends object, Response extends object>(
[fetchFunc]
);

const update = () => wrappedFunc(paramObj);

useEffect(() => {
wrappedFunc(paramObj);
}, [wrappedFunc, paramObj]);

return { isLoading, error, data, update };
return { isLoading, error, data, query };
}
15 changes: 9 additions & 6 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AppProps } from "next/app";
import localFont from "next/font/local";
import Head from "next/head";
import { MediaProvider } from "@/store/MediaContext";
import Layout from "@/components/layout/Layout";
import "@/styles/reset.css";
import "@/styles/variable.css";
Expand All @@ -23,13 +24,15 @@ export default function App({ Component, pageProps }: MyAppProps) {
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</Head>
{Component.isNotLayout ? (
<Component {...pageProps} />
) : (
<Layout>
<MediaProvider>
{Component.isNotLayout ? (
<Component {...pageProps} />
</Layout>
)}
) : (
<Layout>
<Component {...pageProps} />
</Layout>
)}
</MediaProvider>
</>
);
}
36 changes: 36 additions & 0 deletions src/store/MediaContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createContext, useState, useEffect, ReactNode } from "react";

export type MediaType = "PC" | "TABLET" | "MOBILE";

export const MediaContext = createContext<MediaType | undefined>(undefined);

interface MediaProviderProps {
children: ReactNode;
}

export function MediaProvider({ children }: MediaProviderProps) {
const [media, setMedia] = useState<MediaType>();

useEffect(() => {
const checkMedia = (width: number): MediaType => {
if (width >= 1200) return "PC";
if (width >= 768) return "TABLET";
return "MOBILE";
};

const handleWindowResize = () => {
setMedia(checkMedia(window.innerWidth));
};
Comment on lines +15 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3:
가능하면 useEffect 내부의 함수 정의를 외부로 빼주세요~
아래처럼 코드를 입력하면 가독성에 더 좋습니다.

  const checkMedia = (width: number): MediaType => {
    if (width >= 1200) return "PC";
    if (width >= 768) return "TABLET";
    return "MOBILE";
  };

  const handleWindowResize = useCallback(() => {
    setMedia(checkMedia(window.innerWidth));
  }, []);

  useEffect(() => {
    handleWindowResize();

    window.addEventListener("resize", handleWindowResize);
    return () => {
      window.removeEventListener("resize", handleWindowResize);
    };
  }, [handleWindowResize]);


handleWindowResize();

window.addEventListener("resize", handleWindowResize);
return () => {
window.removeEventListener("resize", handleWindowResize);
};
}, []);

return (
<MediaContext.Provider value={media}>{children}</MediaContext.Provider>
);
}
3 changes: 3 additions & 0 deletions src/styles/variable.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@
--line-md: 24px;
--line-sm: 22px;
--line-xs: 18px;

/* Font - Weight */
--semibold: 600;
}
Loading