Skip to content

[고급 레이아웃 컴포넌트] 우스(김영길) 미션 제출합니다.#89

Merged
hozzijeong merged 53 commits into
woowacourse:gilpop8663from
Gilpop8663:step2
Oct 4, 2023
Merged

[고급 레이아웃 컴포넌트] 우스(김영길) 미션 제출합니다.#89
hozzijeong merged 53 commits into
woowacourse:gilpop8663from
Gilpop8663:step2

Conversation

@Gilpop8663

Copy link
Copy Markdown

안녕하세요 클린~!

npm 패키지 사이트

https://www.npmjs.com/package/wus-layout-component

스토리북 문서

https://gilpop8663.github.io/layout-component/?path=/docs/intro--docs

설치 방법

npm i wus-layout-component styled-components -D

🎯 2단계. 고급 레이아웃 컴포넌트

공통

  • 의미있는 커밋 메시지 작성
  • PR에 관련 없는 변경 사항이 포함 유무 확인

컴포넌트 요구사항

  • 선택한 컴포넌트의 기능 구현
  • npm 배포
  • README.md에 코드 저자로서 특히 고민한 부분과 의도 설명
  • 테스트 코드를 작성하였나요? (선택 사항)

📌 구현한 내용 설명

MasonryLayout 컴포넌트

의도하였던 사용자는 핀터레스트, 언스플레시와 같은 화면을 구현하는 개발자로 타겟을 잡았습니다.

처음에는 flex, flex와 같이 해야하나 싶었는데 구현 방법이 떠오르지 않아서 grid로 구현하였습니다. 오늘 오전에 참새의 컴포넌트를 경험해보았는데 많은 영향을 받았습니다. grid로 구현하니 flex를 이용하는 방법에 비해 유연성이 엄청나게 높아진 것을 느꼈어요.

ResizeObserver를 처음 사용해보았는데요 'ResizeObserver'는 요소의 콘텐츠 사각형이 변경될 때 알려줍니다. 그에 따라 대응할 수 있도록 크기를 조정합니다. 와 같은 설명을 할 수 있고요. 아직은 제대로 이해하진 못한 것 같아서 다른 경우에서도 사용해보고 싶은 마음이 듭니다.

그리고 스텝1에서 타입 에러가 나던 부분을 해결해보았는데요. types@react의 타입을 변경하는 형식으로 해결했고, docs 파일에 정리해두었습니다.

MasonryLayout는 아래와 같은 기능들을 고려해서 Props를 설정했습니다

  • 방향을 정한다. row, column - 현재 미구현
  • 최소로 보여질 사이즈를 정한다. 개수는 부모의 너비 / 최소 사이즈로 계산되며 빈 공간 없이 최소 길이 이상으로 넓어진다. itemSize
  • div로 해당 개수만큼 생성하고, flex 방향으로 채운다. 아래쪽이 울퉁불퉁한것은 무한 스크롤을 한다는 가정하에 고려하지 않는다.
  • 이미지 사이즈는 itemSize에 맞추고, 이미지는 비율에 맞게 직사각형으로 조정한다.

패키지 설치 후 자동 완성이 안되는데 얼른 고쳐보도록 하겠습니다. 근데 너무 고통스러워요

📸 스크린샷 (선택 사항)

https://gilpop8663.github.io/layout-component/?path=/docs/masonrylayout--docs

🔗 참고 링크 (선택 사항)

https://wit.nts-corp.com/2022/10/26/6595

https://medium.com/@andybarefoot/a-masonry-style-layout-using-css-grid-8c663d355ebb
https://ellen92.tistory.com/64
https://w3bits.com/css-grid-masonry/
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
https://github.com/woowacourse/layout-component/pull/58/files#diff-914ac3af5acb7507102327d7a0965b7fd543635b8addd127329ef953577f70d3 (참새 PR)

@hozzijeong hozzijeong left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

안녕하세요 우스~! 우스의 학습 방법과 깊이에 대해 감탄을 하고 갑니다... 너무 멋있어요 👍

개인적으로 node_modules의 설정을 바꾼 것이 과감하면서도 멋있으면서도 걱정되네요... 그래도 멋있는 시도라고 생각합니다! (저는 생각도 못해봤을 것 같아요)

코멘트 몇 개 남겼는데 확인 부탁드립니다!!

Comment thread src/lib/MasonryLayout/index.tsx Outdated
Comment on lines +33 to +35
...{
...child.props,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
...{
...child.props,
},
...child.props,

위와 같이 변경할 수 도 있지 않을까요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

디테일하게 봐주셔서 감사합니다 👍

클린이 제안해준 코드로 고쳐볼 수 있을 것 같아요 💯

Comment thread src/lib/MasonryLayout/index.tsx Outdated
{ css, as, children, ...rest }: MasonryLayoutProps<T>,
ref: PolymorphicRef<T>
) {
const childArray = Array.isArray(children) ? children : [children];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

여기서 childArray의 type이 any가 나타나는데, 어느 타입이든 상관이 없는 것일까요?

Masonry의 children에 할당한 값이 ReactElement속성이 아닌 일반적인 string 형태가 오게 된다면 어떻게 되는지 궁금합니다!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

childArray가 any인지 몰랐는데요. 타입 방어를 해야겠네요! 알려주셔서 감사해요 👍

그리고 일반적인 string 형태가 왔을 때 에러가 나고 출력이 되지 않네요 ! 🥲

      <MasonryLayout gap="10px" itemSize="25%" fullScreen as="div">
        안녕하세요안녕하세요안녕하세요안녕하세요안녕하세요안녕하세요
      </MasonryLayout>
image

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

리팩터링 후 문자열도 출력되도록 했습니다

    <MasonryLayout gap="10px" itemSize={300} fullScreen as="div">
        안녕안녕
      </MasonryLayout>

console.log(children)을 한 사진

image

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

수정한 코드입니다

수정 전

onst MasonryLayout: MasonryLayoutComponent = forwardRef(function MasonryLayout<
  T extends ElementType = 'div'
>(
  { css, as, children, ...rest }: MasonryLayoutProps<T>,
  ref: PolymorphicRef<T>
) {
  const childArray = Array.isArray(children) ? children : [children];

  return (
    <S.Component as={as} ref={ref} style={css} {...rest}>
      {childArray.map((child) => (
        <MasonryLayoutItem {...rest}>
          {createElement(child.type, child.props)}
        </MasonryLayoutItem>
      ))}
    </S.Component>
  );
});

수정 후

const MasonryLayout: MasonryLayoutComponent = forwardRef(function MasonryLayout<
  T extends ElementType = 'div'
>(
  { css, as, children, ...rest }: MasonryLayoutProps<T>,
  ref: PolymorphicRef<T>
) {
  const isChildrenArray = Array.isArray(children);

  const childArray: ReactElement[] = isChildrenArray ? children : [children];

  if (!isChildrenArray) {
    return (
      <S.Component as={as} ref={ref} style={css} {...rest}>
        {children}
      </S.Component>
    );
  }

  return (
    <S.Component as={as} ref={ref} style={css} {...rest}>
      {childArray.map((child) => (
        <MasonryLayoutItem {...rest}>
          {createElement(child.type, child.props)}
        </MasonryLayoutItem>
      ))}
    </S.Component>
  );
});

Comment thread src/lib/MasonryLayout/index.tsx Outdated
Comment on lines +6 to +7
export interface _MasonryLayoutProps {
itemSize: string;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

itemSize를 px이 아닌 %로 받으면 화면 축소 시에 화면이 작아져도 이미지의 열은 그대로고 이미지 자체가 기괴(?)하게 줄어드는데, Masonry의 경우에는 이미지를 그대로 보존하고 위치가 달라지는 것이 좀 더 낫지 않을까 생각이 듭니다. 혹시 px로 고정값을 받는 것에 대해서는 어떻게 생각하시나요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

PC에서는 300px, 모바일에서는 200px과 같이 최소 너비를 반응형으로 처리하고 싶었는데요. 이와 비슷하게 %를 사용하면 반응형이 되겠다라고 생각했는데 이것보단, 따로 Props를 받아서 반응형을 구현하는 것이 좋겠다고 생각이 들었습니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

그래서 클린의 제안대로 px로만 가능하도록 변경하려고 합니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

itemSize는 px만 받도록 하였고, 화면의 너비마다 다른 px을 줄 수 있도록 다양한 props를 추가해주었습니다

export interface _MasonryLayoutProps {
  itemSize: number;
  smallItemSize?: number;
  mediumItemSize?: number;
  largeItemSize?: number;
  xLargeItemSize?: number;
  doubleXLargeItemSize?: number;
  gap?: string;
  smallGap?: string;
  mediumGap?: string;
  largeGap?: string;
  xLargeGap?: string;
  doubleXLargeGap?: string;
  rowGap?: string;
  smallRowGap?: string;
  mediumRowGap?: string;
  largeRowGap?: string;
  xLargeRowGap?: string;
  doubleXLargeRowGap?: string;
  columnGap?: string;
  smallColumnGap?: string;
  mediumColumnGap?: string;
  largeColumnGap?: string;
  xLargeColumnGap?: string;
  doubleXLargeColumnGap?: string;
}

args: {
itemSize: '300px',
fullScreen: true,
p: '36px',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

p는 무엇을 의미하나요??

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

p는 패딩을 뜻하는데요 문서화를 해놓지 않아서 사람들이 헷갈릴 것 같네요 jsDoc과 함께 스토리북에 문서화도 해놓겠습니다 👍

Comment thread docs/타입 관련 에러 해결.md Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

와 우스 엄청납니다... 상당히 많은 감명을 받았습니다. 저의 모습을 보니 부끄러워 지는군요...

다만, 궁금한 점은 분명히 ReactNode와 ReactElement의 타입이 수행하는 역할이 다른데, 이 부분을 임의로 바꿨을 때 어떤 사이드 이펙트는 없는지 궁금합니다.

We don't just use ComponentType or FunctionComponent types because you are not supposed to attach
statics to this object, but rather to the original function.

위에 있는 주석에 따르면ExoticComponent를 사용하는 다른 컴포넌트들 (memo, context, forwardRef)에서 영향이 없을지 의문이긴 합니다. 실제 주석에 달려있는 코드의 내용을 미루어서 보면 리액트팀에서도 해당 값을 일반적인 컴포넌트 (ReactElement)로 반환하고 싶지만, 정적인 값을 넘기는 방법이 권장되지 않는다는 내용인데, 혹시 어떻게 생각하시나요?? (제 해석이 틀렸을 수도 있습니다)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@types/react 17버전에서는 ReactElement | null로 되어 있는데요
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts

@types/react 18버전에서는 ReactNode로 바뀌었네요! ㅠㅠ

아래의 PR에서 머지가 되었는데요

DefinitelyTyped/DefinitelyTyped@443451c

해당 PR의 이슈를 보면 이러이러한 내용으로 바꿨다고 하는데 이해는 못했습니다

DefinitelyTyped/DefinitelyTyped#65135

참고: 이 변경 사항은 TypeScript 5.1 이상에만 적용됩니다



TypeScript 5.1에서 요소 유형이 올바른지 확인하기 위해 사용하는 JSX 네임스페이스 
아래에 새 ElementType을 추가합니다. 이렇게 하면 함수 구성 요소, forwardRef 구성
 요소 등이 Render에서 ReactNode( 문자열, 배열, 숫자, 부울, 정의되지 않음)를 반환할 
수 있습니다. 클래스 구성 요소의 경우 이미 의도한 대로 작동했기 때문에 아무것도 
변경되지 않습니다.

하지만 안되었던 이유는 찾았어요!

Vite로 설치한 배포할 때 사용하는 프로젝트에서는 최신의 @types/react를 사용하여서 "@types/react": "^18.2.15", 환경에서는 ReactNode | null 로 했을 때 잘 되어서 에러가 나지 않았는데요

막상 배포하고 실험하기 위해 사용했던 react-lunch 프로젝트에서는 에러가 났었어요. 점심뭐먹지 리엑트 미션이니깐 4~5월인 것 같은데요 위의 PR 머지가 된 기간이 4개월 전이니 해당 폴더에서는 ExoticComponent의 타입이 ReactElement | null로 되어 있어서 배포가 잘못되었다고 생각이 들었었던 것이였네요!

방금 최신의 vite 환경에서 제 패키지를 설치하고 ReactNode로 바꾸어서 사용하니 잘 작동이 되는 것을 확인했어요

ReactNode로 바꾼 코드 이미지

image

빨간 줄이 안보이는 것을 확인할 수 있는 이미지

image

그리고 현재 최신 버전에서 ExoticComponent의 타입이 ReactNode인데 패키지 컴포넌트 반환 타입을 ReactElement | null을 하여도 에러가 나지 않는 이유는 ReactNode에 ReactElement가 포함되기 때문에 에러가 나지 않는 것을 확인할 수 있었습니다

클린 덕분에 왜 배포하는 곳에서는 에러가 안나고, 배포한 곳에서 에러가 나는지 명확히 이유를 알 수 있었습니다

감사해요

🌊🌊🌊

@Gilpop8663 Gilpop8663 left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

안녕하세요 클린 코드 리뷰 해주셔서 감사합니다 ㅎㅎ

변경된 점으로는

  • 다양한 너비에서 반응형이 되도록 함
  • resize할 때 너무 실시간으로 height 값이 반응하다보니 버벅이는 것처럼 보였는데요. 이를 방지하고자 디바운스를 적용했습니다

Comment thread src/lib/MasonryLayout/index.tsx Outdated
Comment on lines +33 to +35
...{
...child.props,
},

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

디테일하게 봐주셔서 감사합니다 👍

클린이 제안해준 코드로 고쳐볼 수 있을 것 같아요 💯

args: {
itemSize: '300px',
fullScreen: true,
p: '36px',

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

p는 패딩을 뜻하는데요 문서화를 해놓지 않아서 사람들이 헷갈릴 것 같네요 jsDoc과 함께 스토리북에 문서화도 해놓겠습니다 👍

Comment thread src/lib/MasonryLayout/index.tsx Outdated
Comment on lines +6 to +7
export interface _MasonryLayoutProps {
itemSize: string;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

PC에서는 300px, 모바일에서는 200px과 같이 최소 너비를 반응형으로 처리하고 싶었는데요. 이와 비슷하게 %를 사용하면 반응형이 되겠다라고 생각했는데 이것보단, 따로 Props를 받아서 반응형을 구현하는 것이 좋겠다고 생각이 들었습니다

Comment thread src/lib/MasonryLayout/index.tsx Outdated
Comment on lines +6 to +7
export interface _MasonryLayoutProps {
itemSize: string;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

그래서 클린의 제안대로 px로만 가능하도록 변경하려고 합니다

Comment thread src/lib/MasonryLayout/index.tsx Outdated
{ css, as, children, ...rest }: MasonryLayoutProps<T>,
ref: PolymorphicRef<T>
) {
const childArray = Array.isArray(children) ? children : [children];

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

childArray가 any인지 몰랐는데요. 타입 방어를 해야겠네요! 알려주셔서 감사해요 👍

그리고 일반적인 string 형태가 왔을 때 에러가 나고 출력이 되지 않네요 ! 🥲

      <MasonryLayout gap="10px" itemSize="25%" fullScreen as="div">
        안녕하세요안녕하세요안녕하세요안녕하세요안녕하세요안녕하세요
      </MasonryLayout>
image

Comment thread src/lib/MasonryLayout/index.tsx Outdated
{ css, as, children, ...rest }: MasonryLayoutProps<T>,
ref: PolymorphicRef<T>
) {
const childArray = Array.isArray(children) ? children : [children];

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

리팩터링 후 문자열도 출력되도록 했습니다

    <MasonryLayout gap="10px" itemSize={300} fullScreen as="div">
        안녕안녕
      </MasonryLayout>

console.log(children)을 한 사진

image

Comment thread src/lib/MasonryLayout/index.tsx Outdated
{ css, as, children, ...rest }: MasonryLayoutProps<T>,
ref: PolymorphicRef<T>
) {
const childArray = Array.isArray(children) ? children : [children];

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

수정한 코드입니다

수정 전

onst MasonryLayout: MasonryLayoutComponent = forwardRef(function MasonryLayout<
  T extends ElementType = 'div'
>(
  { css, as, children, ...rest }: MasonryLayoutProps<T>,
  ref: PolymorphicRef<T>
) {
  const childArray = Array.isArray(children) ? children : [children];

  return (
    <S.Component as={as} ref={ref} style={css} {...rest}>
      {childArray.map((child) => (
        <MasonryLayoutItem {...rest}>
          {createElement(child.type, child.props)}
        </MasonryLayoutItem>
      ))}
    </S.Component>
  );
});

수정 후

const MasonryLayout: MasonryLayoutComponent = forwardRef(function MasonryLayout<
  T extends ElementType = 'div'
>(
  { css, as, children, ...rest }: MasonryLayoutProps<T>,
  ref: PolymorphicRef<T>
) {
  const isChildrenArray = Array.isArray(children);

  const childArray: ReactElement[] = isChildrenArray ? children : [children];

  if (!isChildrenArray) {
    return (
      <S.Component as={as} ref={ref} style={css} {...rest}>
        {children}
      </S.Component>
    );
  }

  return (
    <S.Component as={as} ref={ref} style={css} {...rest}>
      {childArray.map((child) => (
        <MasonryLayoutItem {...rest}>
          {createElement(child.type, child.props)}
        </MasonryLayoutItem>
      ))}
    </S.Component>
  );
});

Comment thread src/lib/MasonryLayout/index.tsx Outdated
Comment on lines +6 to +7
export interface _MasonryLayoutProps {
itemSize: string;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

itemSize는 px만 받도록 하였고, 화면의 너비마다 다른 px을 줄 수 있도록 다양한 props를 추가해주었습니다

export interface _MasonryLayoutProps {
  itemSize: number;
  smallItemSize?: number;
  mediumItemSize?: number;
  largeItemSize?: number;
  xLargeItemSize?: number;
  doubleXLargeItemSize?: number;
  gap?: string;
  smallGap?: string;
  mediumGap?: string;
  largeGap?: string;
  xLargeGap?: string;
  doubleXLargeGap?: string;
  rowGap?: string;
  smallRowGap?: string;
  mediumRowGap?: string;
  largeRowGap?: string;
  xLargeRowGap?: string;
  doubleXLargeRowGap?: string;
  columnGap?: string;
  smallColumnGap?: string;
  mediumColumnGap?: string;
  largeColumnGap?: string;
  xLargeColumnGap?: string;
  doubleXLargeColumnGap?: string;
}

Comment thread docs/타입 관련 에러 해결.md Outdated

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@types/react 17버전에서는 ReactElement | null로 되어 있는데요
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts

@types/react 18버전에서는 ReactNode로 바뀌었네요! ㅠㅠ

아래의 PR에서 머지가 되었는데요

DefinitelyTyped/DefinitelyTyped@443451c

해당 PR의 이슈를 보면 이러이러한 내용으로 바꿨다고 하는데 이해는 못했습니다

DefinitelyTyped/DefinitelyTyped#65135

참고: 이 변경 사항은 TypeScript 5.1 이상에만 적용됩니다



TypeScript 5.1에서 요소 유형이 올바른지 확인하기 위해 사용하는 JSX 네임스페이스 
아래에 새 ElementType을 추가합니다. 이렇게 하면 함수 구성 요소, forwardRef 구성
 요소 등이 Render에서 ReactNode( 문자열, 배열, 숫자, 부울, 정의되지 않음)를 반환할 
수 있습니다. 클래스 구성 요소의 경우 이미 의도한 대로 작동했기 때문에 아무것도 
변경되지 않습니다.

하지만 안되었던 이유는 찾았어요!

Vite로 설치한 배포할 때 사용하는 프로젝트에서는 최신의 @types/react를 사용하여서 "@types/react": "^18.2.15", 환경에서는 ReactNode | null 로 했을 때 잘 되어서 에러가 나지 않았는데요

막상 배포하고 실험하기 위해 사용했던 react-lunch 프로젝트에서는 에러가 났었어요. 점심뭐먹지 리엑트 미션이니깐 4~5월인 것 같은데요 위의 PR 머지가 된 기간이 4개월 전이니 해당 폴더에서는 ExoticComponent의 타입이 ReactElement | null로 되어 있어서 배포가 잘못되었다고 생각이 들었었던 것이였네요!

방금 최신의 vite 환경에서 제 패키지를 설치하고 ReactNode로 바꾸어서 사용하니 잘 작동이 되는 것을 확인했어요

ReactNode로 바꾼 코드 이미지

image

빨간 줄이 안보이는 것을 확인할 수 있는 이미지

image

그리고 현재 최신 버전에서 ExoticComponent의 타입이 ReactNode인데 패키지 컴포넌트 반환 타입을 ReactElement | null을 하여도 에러가 나지 않는 이유는 ReactNode에 ReactElement가 포함되기 때문에 에러가 나지 않는 것을 확인할 수 있었습니다

클린 덕분에 왜 배포하는 곳에서는 에러가 안나고, 배포한 곳에서 에러가 나는지 명확히 이유를 알 수 있었습니다

감사해요

🌊🌊🌊

@hozzijeong hozzijeong left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

안녕하세요 우스~

리뷰가 많이 늦었습니다 (죄송합니다 ㅠ)

바뀐 코드 잘 봤습니다!! 실제로 작동시켜보니 너무 잘 되더라구요~

그럼 이제 그만 다음 단계로 넘어가시죠!! 고생 많이하셨습니다!

Comment on lines +19 to +28
const debounce = (func: any, timeout = 300) => {
let timer: NodeJS.Timeout;

return (...args: any[]) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

👍

Comment on lines +41 to +90

@media (min-width: 640px) {
grid-template-columns: ${({ smallItemSize }) =>
getGridTemplate(smallItemSize)};
grid-column-gap: ${({ smallGap, smallColumnGap }) =>
getGridColumGap({
responsiveGap: smallGap,
responsiveColumnGap: smallColumnGap,
})};
}

@media (min-width: 768px) {
grid-template-columns: ${({ mediumItemSize }) =>
getGridTemplate(mediumItemSize)};
grid-column-gap: ${({ mediumGap, mediumColumnGap }) =>
getGridColumGap({
responsiveGap: mediumGap,
responsiveColumnGap: mediumColumnGap,
})};
}

@media (min-width: 1024px) {
grid-template-columns: ${({ largeItemSize }) =>
getGridTemplate(largeItemSize)};
grid-column-gap: ${({ largeGap, largeColumnGap }) =>
getGridColumGap({
responsiveGap: largeGap,
responsiveColumnGap: largeColumnGap,
})};
}

@media (min-width: 1280px) {
grid-template-columns: ${({ xLargeItemSize }) =>
getGridTemplate(xLargeItemSize)};
grid-column-gap: ${({ xLargeGap, xLargeColumnGap }) =>
getGridColumGap({
responsiveGap: xLargeGap,
responsiveColumnGap: xLargeColumnGap,
})};
}

@media (min-width: 1536px) {
grid-template-columns: ${({ doubleXLargeItemSize }) =>
getGridTemplate(doubleXLargeItemSize)};
grid-column-gap: ${({ doubleXLargeGap, doubleXLargeColumnGap }) =>
getGridColumGap({
responsiveGap: doubleXLargeGap,
responsiveColumnGap: doubleXLargeColumnGap,
})};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

세세한 반응형 대응까지...👍

@hozzijeong hozzijeong merged commit d7e361d into woowacourse:gilpop8663 Oct 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants