๐Ÿšค ์„ฑ์žฅ์ผ์ง€ 7.0

์ฑ… ํ–‰๋ณตํ•œ ์ด๊ธฐ์ฃผ์˜์ž(์›จ์ธ ๋‹ค์ด์–ด)์˜ ๋‚ด์šฉ์— ์ž๊ทน๋ฐ›์•„ ์‹œ์ž‘ํ•˜๋Š” ์†Œ๋ฐ•ํ•œ ์„ฑ์žฅ๊ธฐ๋ก

์‚ด์•„์žˆ๋Š” ๊ฝƒ๊ณผ ์ฃฝ์€ ๊ฝƒ์€ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ณ„ํ•˜๋Š”๊ฐ€?
์„ฑ์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์‚ด์•„ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
์ƒ๋ช…์˜ ์œ ์ผํ•œ ์ฆ๊ฑฐ๋Š” ์„ฑ์žฅ์ด๋‹ค!

โš› (7.0)<์™„์ „ ๊ฐœํŽธ> ํŒŒ์ธ๋งŒ ํ•™์Šต๋ฒ•์„ ์•Œ๊ฒŒ ๋œ๋งŒํผ, ์„ฑ์žฅ์ผ์ง€๋Š” ์ •๋ง ๊ทธ ๋‚ ์˜ ํ‚ค์›Œ๋“œ ์ค‘์‹ฌ์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.

Swiper ์‚ฌ์šฉ ํ›„๊ธฐ

๊ธฐ์กด react๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•Œ๋Š” ์—ด์‹ฌํžˆ ์ ์šฉํ•ด๋ณด๋ ค๋‹ค๊ฐ€ ๊ณ„์† ui๊ฐ€ ๊นจ์ ธ์„œ ํฌ๊ธฐํ•˜๊ณ  ์ง์ ‘ Carousel ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค. ์ง์ ‘ ๊ตฌํ˜„ํ•œ ๊ฒƒ๊นŒ์ง„ ์ข‹์€๋ฐ, ์•„๋ฌด๋ž˜๋„ touch slide๋‚˜ ํ™•์žฅ์„ฑ๋ฉด์—์„œ ์™„์„ฑ๋„๊ฐ€ ๋งŽ์ด ๋–จ์–ด์กŒ๋‹ค.(์กฐ๊ธˆ๋งŒ ๊ฑด๋“œ๋ ค๋„ ๋ถ€์„œ์งˆ ๊ฒƒ๋งŒ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธโ€ฆ) ๊ทธ๋ž˜์„œ ์ด๋ฒˆ์—” ๋‹ค์‹œ ๊ฐ์žก๊ณ !!! swiper๋ฅผ ์—ด์‹ฌํžˆ ๋œฏ์–ด๋ณด๋ฉด์„œ ์ ์šฉํ•ด๋ณด์•˜๋‹ค. ํ•˜โ€ฆ ์ด๋ ‡๊ฒŒ ํŽธํ•˜๊ณ  ์‰ฌ์šด ๊ฑด ์ค„ ์•Œ์•˜๋”๋ผ๋ฉดโ€ฆ ํ—ˆํ—ˆ

์šฐ์„  swiper์—์„œ๋Š” ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ module๋“ค์„ ์ง€์›ํ•˜๊ณ  ์žˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์ถ”๊ฐ€ 1) ๋ณดํ†ต slide๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•˜๋ ค๊ณ  onSlideChange๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, ์ด๊ฑด slide๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์œ ์ €๊ฐ€ slide๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ๋งˆ์šฐ์Šค๋ฅผ ๋–ผ๋Š” ์ˆœ๊ฐ„์—๋งŒ ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋ž˜์„œ onRealIndexChange๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

// ์ƒ๋žต

<Swiper
  className="h-full w-full"
  modules={[Autoplay, A11y]}
  autoplay={{ delay: SWIPER.DELAY, disableOnInteraction: false }}
  spaceBetween={bodyWidth < 390 ? bodyWidth : SWIPER.SPACE_BETWEEN}
  slidesPerView={SWIPER.SLIDES_PER_VIEW}
  loop={true}
  loopedSlides={SWIPER.LOOPED_SLIDES}
  onRealIndexChange={swiper => {
    setCurrentSlideIndex(swiper.realIndex);
  }}
>

// ์ƒ๋žต

๊ทธ๋ฆฌ๊ณ  ๋˜ ํ•˜๋‚˜ ๊ธฐ์–ตํ•˜๋ฉด ์ข‹์„ ๊ฒƒ! swiper ์ปดํฌ๋„ŒํŠธ์— tailwindcss์˜ className์œผ๋กœ display ์†์„ฑ์„ ์ ์šฉํ•˜๋Š” ๊ฑด ๋˜์ง€ ์•Š๋Š”๋‹ค. ์•„๋งˆ ๊ธฐ๋ณธ์ ์ธ ์„ค์ • ์ž์ฒด๊ฐ€ block์œผ๋กœ ๋˜์–ด์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜์„œ display ์†์„ฑ์„ ์ ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด style ์†์„ฑ์œผ๋กœ ์ง์ ‘ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค.

<SwiperSlide
  key={index}
  className="flex h-full w-full items-center justify-center"
  // NOTE: Swiper ์ปดํฌ๋„ŒํŠธ์˜ display๋Š” ํ…Œ์ผ์œˆ๋“œ ํด๋ž˜์Šค๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
  style={{ display: 'flex' }}
  onClick={() => {
    if (currentSlideIndex !== index) {
      return;
    }
    if (clickedSlideIndex !== index) {
      setClickedSlideIndex(index);
      return;
    }
    setClickedSlideIndex(-1);
  }}
>
// ์ƒ๋žต

httpClient๋กœ ํ™•์žฅ์„ฑ ์ƒ๊ฐํ•˜๊ธฐ(์ถ”ํ›„ ์˜์กด์„ฑ ์ฃผ์ž…๋„ ๊ณ ๋ คํ•ด๋ณด๊ธฐ)

์•„๋ž˜์™€ ๊ฐ™์ด api ํ†ต์‹ ํ•˜๋Š” ๋กœ์ง์„ ๊ด€๋ฆฌํ•˜๋ฉด ๋” ๊น”๋”ํ•˜๊ฒŒ ์ถ”์ƒํ™”๊ฐ€ ๋ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‚˜์ค‘์— ๋‹ค๋ฅธ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์•„์ง„๋‹ค.

export class HttpClient {
  private baseUrl: string;
  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  fetch(path: string, options = {}) {
    return fetch(`${this.baseUrl}${path}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }
}

์•„๋ž˜๋Š” ์œ„์˜ HttpClient ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ด๋‹ค.

import { HttpClient } from '../http';

export async function getRecommendations() {
  if (!process.env.NEXT_PUBLIC_BASE_API_URL) throw new Error('์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.');

  const httpClient = new HttpClient(process.env.NEXT_PUBLIC_BASE_API_URL);
  const response = await httpClient.fetch('/recommendations');
  const json = await response.json();
  return json.body;
}

๊ณ ๋ฏผ: ์—ฌ๋Ÿฌ ๊ธฐ๊ธฐ์— ๋Œ€์‘ํ•˜๊ธฐ

swiper๋ฅผ ํ†ตํ•ด Carousel ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ, ํ˜„์žฌ slide์˜ ์–‘ ์˜† slide์— ๋Œ€ํ•œ style์„ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์„ ํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋‹ค์–‘ํ•œ ํ™”๋ฉดํฌ๊ธฐ์— ๋”ฐ๋ผ Carousel ์ปดํฌ๋„ŒํŠธ์˜ ui๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์กฐ์ •ํ•˜๋Š” ๊ฒŒ ์ •๋ง ์–ด๋ ค์› ๋‹ค.(์ง€๊ธˆ๋„ ์–ด๋А์ •๋„๋งŒ ๋Œ€์‘ํ–ˆ์ง€โ€ฆ ์™„๋ฒฝํ•˜๊ฒŒ๋Š” ๋ชปํ–ˆ๋‹ค.) ๊ธฐ๊ธฐ๋งˆ๋‹ค ๋‹ค๋ฅธ ํ™”๋ฉด์— ๋Œ€ํ•ด์„œ๋Š” ์‹ค์ œ ํ˜„์—…์—์„  ์–ด๋–ป๊ฒŒ ๋Œ€์‘ํ• ์ง€ ๋„ˆ๋ฌด ์•Œ๊ณ ์‹ถ๋‹ค. ๊ทธ์ € media query๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ์Šค๋งˆํŠธํฐ์˜ ํ™”๋ฉด์ด ๋„ˆ๋ฌด ๋‹ค์–‘ํ•œ๋ฐโ€ฆ ํ  ๊ณ„์† ์ด ๋ถ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ• ์ง€ ์ฐพ์•„๋ด์•ผ๊ฒ ๋‹ค.

๐Ÿ“ ํšŒ๊ณ 

์‚ฌ์‹ค ์œ„์˜ ๋‚ด์šฉ๋ง๊ณ ๋„ Carousel์—์„œ ์‚ฌ์šฉ๋˜๋Š” image ํฌ๊ธฐ ์กฐ์ ˆ๋ถ€ํ„ฐ ์งœ์ž˜ํ•œ tailwind ์˜ค๋ฅ˜๊นŒ์ง€โ€ฆ ๋งŽ์•˜์ง€๋งŒ ์ด๊ฑด Carousel ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •๋ฆฌํ•  ๋•Œ ํ•œ๋ฒˆ์— ์ž‘์„ฑํ•ด์•ผ๊ฒ ๋‹ค. ๊ทธ๋‚˜์ €๋‚˜ ์˜ค๋Š˜์€ ์ง„์งœ ์ผ์ฐ ์ž๋ คํ–ˆ๋Š”๋ฐโ€ฆ ์–ผ๋ฅธ ์ž์•ผ์ง€!!!

์ฐธ๊ณ