-
Notifications
You must be signed in to change notification settings - Fork 26
[한장희] sprint6 #131
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
[한장희] sprint6 #131
The head ref may contain hidden characters: "React-\uD55C\uC7A5\uD76C-sprint5"
Conversation
|
스프리트 미션 하시느라 수고 많으셨어요. |
| <ProductGrid | ||
| products={products} | ||
| gridSize={responsiveValues.bestPicContainerSize} | ||
| picSize={responsiveValues.bestPicSize} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(참고만 해도 됩니다 😉)ProductGrid에 gridSize, picSize가 드릴링이 되는 것 같아서 한 번 리팩토링 해봤습니다 !
diff --git a/vite-project/src/components/BestProductSection/BestProducts.jsx b/vite-project/src/components/BestProductSection/BestProducts.jsx
index 82f5c22..468fddc 100644
--- a/vite-project/src/components/BestProductSection/BestProducts.jsx
+++ b/vite-project/src/components/BestProductSection/BestProducts.jsx
@@ -1,17 +1,30 @@
-import { useResponsivePage } from "../../hooks/useResponsivePage";
import ProductGrid from "../common/ProductGrid";
+import ProductCard from "../common/ProductCard";
+import { useResponsivePage } from "../../hooks/useResponsivePage";
+import { DEVICE_STYLES } from "../common/DeviceClasses";
const BestProducts = ({ products }) => {
- const responsiveValues = useResponsivePage();
+ const { device } = useResponsivePage();
+
+ const containerClass = DEVICE_STYLES[device].best.container;
+ const pictureClass = DEVICE_STYLES[device].best.picture;
return (
<div className="flex flex-col gap-3 ">
<h2 className="text-xl font-bold ">베스트 상품</h2>
- <ProductGrid
- products={products}
- gridSize={responsiveValues.bestPicContainerSize}
- picSize={responsiveValues.bestPicSize}
- />
+ <ProductGrid>
+ {products.map((product) => (
+ <ProductCard
+ key={product.id}
+ className={containerClass}
+ name={product.name}
+ price={product.price}
+ favoriteCount={product.favoriteCount}
+ images={product.images}
+ picSizeClass={pictureClass}
+ />
+ ))}
+ </ProductGrid>
</div>
);
};diff --git a/vite-project/src/components/ProductListSection/Container.jsx b/vite-project/src/components/ProductListSection/Container.jsx
index 0d02c77..905a802 100644
--- a/vite-project/src/components/ProductListSection/Container.jsx
+++ b/vite-project/src/components/ProductListSection/Container.jsx
@@ -2,12 +2,14 @@ import { useState } from "react";
import useGetProducts from "../../hooks/useGetProducts";
import usePagination from "../../hooks/usePagination";
import ProductGrid from "../common/ProductGrid";
+import ProductCard from "../common/ProductCard";
import Pagination from "../ProductListSection/Pagination";
import searchIcon from "../../assets/searchIcon.svg";
import Dropdown from "./Dropdown";
-import { useResponsivePage } from "../../hooks/useResponsivePage";
import { Link } from "react-router-dom";
import { SORT_OPTIONS } from "../../constant/SORT_OPTIONS";
+import { useResponsivePage } from "../../hooks/useResponsivePage";
+import { DEVICE_STYLES } from "../common/DeviceClasses";
const Container = ({ pageSize, isMobile }) => {
const [orderBy, setOrderBy] = useState(SORT_OPTIONS[0].value);
@@ -17,7 +19,10 @@ const Container = ({ pageSize, isMobile }) => {
orderBy,
currentPage,
});
- const ResponsiveValues = useResponsivePage();
+ const { device } = useResponsivePage();
+
+ const containerClass = DEVICE_STYLES[device].normal.container;
+ const pictureClass = DEVICE_STYLES[device].normal.picture;
const handleSelect = (val) => {
console.log("$$", val);
@@ -92,11 +97,19 @@ const Container = ({ pageSize, isMobile }) => {
</div>
)}
- <ProductGrid
- products={products}
- picSize={ResponsiveValues.normalPicSize}
- gridSize={ResponsiveValues.normalPicContainerSize}
- />
+ <ProductGrid>
+ {products.map((product) => (
+ <ProductCard
+ key={product.id}
+ className={containerClass}
+ name={product.name}
+ price={product.price}
+ favoriteCount={product.favoriteCount}
+ images={product.images}
+ picSizeClass={pictureClass}
+ />
+ ))}
+ </ProductGrid>
<Pagination
currentPage={currentPage}
setCurrentPage={setCurrentPage}diff --git a/vite-project/src/components/common/ProductGrid.jsx b/vite-project/src/components/common/ProductGrid.jsx
index 3b5835d..871a009 100644
--- a/vite-project/src/components/common/ProductGrid.jsx
+++ b/vite-project/src/components/common/ProductGrid.jsx
@@ -1,30 +1,7 @@
-import ProductCard from "./ProductCard";
-import { GRID_SIZES } from "./ProductGridClasses";
-import { PIC_SIZES } from "./ProductGridClasses";
-
-const ProductGrid = ({
- gridSize = "grid224",
- picSize = "normalPicSize",
- products,
-}) => {
- const sizeClass = GRID_SIZES[gridSize] || "";
- const picSizeClass = PIC_SIZES[picSize] || "";
-
+const ProductGrid = ({ children }) => {
return (
<div className="flex flex-wrap justify-center gap-5">
- {products.map((product) => {
- return (
- <ProductCard
- key={product.id}
- className={`${sizeClass}`}
- name={product.name}
- price={product.price}
- favoriteCount={product.favoriteCount}
- images={product.images}
- picSizeClass={picSizeClass}
- />
- );
- })}
+ {children}
</div>
);
};diff --git a/vite-project/src/components/common/ProductGridClasses.js b/vite-project/src/components/common/ProductGridClasses.js
deleted file mode 100644
index 8ad09e3..0000000
--- a/vite-project/src/components/common/ProductGridClasses.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export const GRID_SIZES = {
- grid168: "w-[168px]",
- grid224: "w-56 h-72",
- grid228: "w-72 h-[378px]",
- grid343: "w-[343px] h-[434px]",
-};
-
-export const PIC_SIZES = {
- normalPicSize: "w-56 h-56 ",
- normalPicMobile: "w-[168px] h-[168px]",
- bestPicSize: "w-[282px] h-[282px]",
- bestPicTabletMobile: "w-[343px] h-[343px]",
-};
diff --git a/vite-project/src/hooks/useResponsivePage.js b/vite-project/src/hooks/useResponsivePage.js
index edf831d..d4ca7ed 100644
--- a/vite-project/src/hooks/useResponsivePage.js
+++ b/vite-project/src/hooks/useResponsivePage.js
@@ -17,6 +17,6 @@ export const useResponsivePage = () => {
return () => window.removeEventListener("resize", onResize);
}, []);
- const values = useMemo(() => CONFIG[device], [device]);
+ const values = useMemo(() => ({ ...CONFIG[device], device }), [device]);
return values;
};핵심은 ProductGrid의 역할이 프롭스를 전달만 해주는 것 같아서요 !
일관적인 스타일 용도로만 사용하도록 바꿔봤습니다 !
참고만 하시고 사용하지 않으셔도 됩니다 😉
| const Input = ({ | ||
| inputTypeStyle = "basic", | ||
| as, | ||
| type, | ||
| id, | ||
| imgUrl, | ||
| onChange, | ||
| onClick, | ||
| onKeyDown, | ||
| ...props | ||
| }) => { | ||
| const styleClass = INPUT_TYPE_STYLE[inputTypeStyle] || ""; | ||
| const Component = as || "input"; | ||
|
|
||
| return ( | ||
| <div> | ||
| {type === "file" ? ( | ||
| <div className="flex gap-8"> | ||
| <div className="flex flex-col gap-4"> | ||
| <label className={`${styleClass} bg-gray-100 cursor-pointer`}> | ||
| <img src={props.src} alt={props.alt} /> | ||
| <Component | ||
| accept="image/*" | ||
| type={type} | ||
| {...props} | ||
| id={id} | ||
| className="hidden" | ||
| onChange={onChange} | ||
| /> | ||
| </label> | ||
| {imgUrl && ( | ||
| <p className="text-red-400"> | ||
| *이미지 등록은 최대 1개까지 가능합니다 | ||
| </p> | ||
| )} | ||
| </div> | ||
| {imgUrl && ( | ||
| <div className="relative"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호. input 외에 다른 컴포넌트로 사용될 수 있도록 해놓으셨군요.
확장성을 고려하신 것 같군요? 장희님을 보면 참 도전적이고 학습에 열려있는 수강생이란 느낌이 많이 들어요 ! 리스펙합니다 🥺
다만, 하나의 컴포넌트에서 많은 역할을 수행하려다 보니 조금 복잡해진 느낌이 없잖아 있군요 !
다음과 같이 분리해보는 것도 고려해보실 수 있을 것 같습니다 😊:
const InputText = ({ styleClass, ...props }) => (
<input className={`${styleClass} bg-gray-100`} {...props} />
);
const InputFile = ({ styleClass, imgUrl, onDelete, ...props }) => (
<div className="flex gap-8">
<div className="flex flex-col gap-4">
<label className={`${styleClass} bg-gray-100 cursor-pointer`}>
<input type="file" className="hidden" {...props} />
</label>
{imgUrl && <p className="text-red-400">*이미지 등록은 최대 1개</p>}
</div>
{imgUrl && (
<div className="relative">
<img src={imgUrl} alt="preview" />
<img src="/ic_X.svg" alt="삭제" onClick={onDelete} />
</div>
)}
</div>
);
export default function Input({ type, ...props }) {
const styleClass = INPUT_TYPE_STYLE[props.inputTypeStyle] || "";
if (type === "file") return <InputFile styleClass={styleClass} {...props} />;
return <InputText styleClass={styleClass} type={type} {...props} />;
}| return ( | ||
| <div> | ||
| <Header /> | ||
| <main className="max-w-screen-xl px-4 mt-6 md:px-6 md:mx-auto"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
크으 ~ 시맨틱 태그도 잊지 않았군요 👍
| const handleHashTagEnter = (e) => { | ||
| if (e.key === "Enter") { | ||
| e.preventDefault(); | ||
| const newTag = e.target.value.trim(); | ||
| if (newTag && !hashtags.includes(newTag)) { | ||
| setHashtags((prev) => [...prev, newTag]); | ||
| e.target.value = ""; | ||
| handleInputChange(); | ||
| } | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사용성까지 고려한 꼼꼼함.. ✨✨
엔터까지 고려하셨군요 ! 🥺
|
크으.. 장희님 수고하셨습니다. 그리고.. 번아웃.. 이시라면서요 ㄷㄷ... 무튼, 이번 미션 정말 수고 많으셨습니다 장희님 💪💪 |
체크리스트 [기본]
체크리스트 [심화]