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

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

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

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

Swiper UX ๊ฐœ์„ 

Swiper๋ฅผ ์ด์šฉํ•ด์„œ Carousel์„ ๊ตฌํ˜„ ํ›„, ๋ฐฐํฌํ•˜์—ฌ ํ•ธ๋“œํฐ์—์„œ ๋™์ž‘์‹œ์ผœ๋ณด์•˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์›ฌ๊ฑธ ์Šฌ๋ผ์ด๋“œ UX๊ฐ€ ๋š๋š ๋Š๊ธฐ๋ฉด์„œ ์ž‘๋™ํ–ˆ๋‹ค. ์ด ๋ถ€๋ถ„์„ ํ˜น์‹œ ๊ณต์‹๋ฌธ์„œ์—์„œ ์ง€์›ํ•˜๋‚˜ ํ•ด์„œ ์ฐพ์•„๋ณด์•˜๋Š”๋ฐ ๋‹คํ–‰ํžˆ cssMode๋ผ๋Š” ์˜ต์…˜์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ์ด ์˜ต์…˜์„ ์ ์šฉํ•˜๋‹ˆ ์Šฌ๋ผ์ด๋“œ UX๊ฐ€ ๋งค๋„๋Ÿฝ๊ฒŒ ๋™์ž‘ํ–ˆ๋‹ค.

ํ™œ์„ฑํ™”ํ•˜๋ฉด ์ตœ์‹  CSS ์Šคํฌ๋กค ์Šค๋ƒ… API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Swiper์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ๊ฐ„๋‹จํ•œ ๊ตฌ์„ฑ์—์„œ ํ›จ์”ฌ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ ์šฉํ•˜๊ณ  ๋‚˜์„œ ์Šฌ๋ผ์ด๋“œ๊ฐ€ ์•„์ฃผ ๋งค๋„๋Ÿฝ๊ฒŒ ๋™์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋‹ค๋งŒ ๋ฌธ์ œ๋Š” ๋ฐ์Šคํฌํƒ‘์—์„œ ํ„ฐ์น˜ ์Šฌ๋ผ์ด๋“œ๊ฐ€ ๋˜์งˆ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ๊ตฌ๊ธ€๋ง๋„ ํ•ด๋ณด๊ณ  ์ด๊ฒƒ์ €๊ฒƒ ๋‹ค ํ•ด๋ดค์ง€๋งŒ cssMode ์ ์šฉ ํ›„์—๋Š” ์–ด์ฉ” ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜๋„ ์œ ์ €์—๊ฒŒ ์Šฌ๋ผ์ด๋“œ๋ฅผ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋Š” UX๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด Navigation ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

return (
<Swiper
  className="h-full w-full"
  modules={[Autoplay, A11y, Navigation, Keyboard]}
  autoplay={{ delay: SWIPER.DELAY, disableOnInteraction: false }}
  freeMode={true}
  navigation={isDesktop}
  keyboard={{ enabled: true }}
  lazyPreloadPrevNext={SWIPER.LAZY_LOADED_PREV_NEXT}
  spaceBetween={bodyWidth < STANDARD.WIDTH ? bodyWidth : SWIPER.SPACE_BETWEEN}
  slidesPerView={SWIPER.SLIDES_PER_VIEW}
  loop={true}
  loopedSlides={SWIPER.LOOPED_SLIDES}
  loopPreventsSliding={true}
  onRealIndexChange={swiper => {
    setCurrentSlideIndex(swiper.realIndex);
  }}
  cssMode={true}
>

Github Issue ์ž๋™ close๋˜๋˜ ๋ฌธ์ œ

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ๊ณ„์† ๋‚ด๊ฐ€ ๋งŒ๋“  ์ด์Šˆ๊ฐ€ ์ž๋™์œผ๋กœ close๊ฐ€ ๋˜์–ด์„œ ์™œ ์ด๋Ÿฌ๋‚˜ ํ–ˆ๋‹ค.(์ง„์ž‘ ์ฐพ์•„๋ณผ๊ฑธโ€ฆ ๋ฐ˜์„ฑ) ์ฒ˜์Œ์—” ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋‹ซํžˆ๋Š”๊ฑด๊ฐ€ ํ–ˆ๋Š”๋ฐ ์•Œ๊ณ ๋ณด๋‹ˆ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์— ์•„๋ž˜์™€ ๊ฐ™์€ ๋‹จ์–ด์™€ ์ด์Šˆ ๋„˜๋ฒ„๋ฅผ ์ ์–ด์ฃผ๋ฉด ์ž๋™์œผ๋กœ close๊ฐ€ ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

  • close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved + #{issue number}: ์ด์Šˆ๋ฅผ ์ž๋™์œผ๋กœ closeํ•œ๋‹ค.

zustand๋ฅผ ํ†ตํ•œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ

์—ฌ๋Ÿฌ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ์ด์ƒํ•˜๊ฒŒ zustand๊ฐ€ ๋•ก๊ธด๋‹ค ํ—ˆํ—ฃโ€ฆ ์ผ๋‹จ ์‚ฌ์šฉ๋ฒ•์ด ์ •๋ง ๊ฐ„๋‹จํ•˜๋ฉด์„œ Redux Devtools๋„ ์ง€์›ํ•˜๊ณ  ๋ฌด์—‡๋ณด๋‹ค demo ์‚ฌ์ดํŠธ๊ฐ€ ์ •๋ง ๋„ˆ๋ฌด ์˜ˆ์˜๋‹คใ…‹ใ…‹ใ…‹ Jotai๋ฅผ ๊ฐœ๋ฐœํ•˜์‹  ๋ถ„์ด๋ž‘ ๋™์ผ์ธ๋ฌผ์ด๋ผ๊ณ  ์•Œ๊ณ  ์žˆ๋Š”๋ฐ, ๋ญ”๊ฐ€ Zustand์— ๋” ๊ณต์„ ๋“ค์ด์‹œ๋Š” ๋Š๋‚Œ..? (๋˜, npm trends๋ฅผ ๋ณด๋ฉด zustand์˜ ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€๊ฐ€ ์ •๋ง ์–ด๋งˆ์–ด๋งˆํ•˜๊ฒŒ ์ฆ๊ฐ€ํ•˜๊ณ  ์žˆ๋‹ค..! ๊ณง Redux ๋”ฐ๋ผ์žก์„๋“ฏ..?) ์ด๋ฒˆ์— Next์™€ ์ฒ˜์Œ์œผ๋กœ ๊ฐ™์ด ์‚ฌ์šฉํ•ด๋ดค๋Š”๋ฐ client ์ปดํฌ๋„ŒํŠธ์—์„œ ์ •๋ง ๊น”๋”ํ•˜๊ฒŒ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋„ˆ์–ด์–ด์–ด์–ด๋ฌด ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค. ์•„๋ž˜๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด๋ณธ ์ฝ”๋“œ์ด๋‹ค.(์œ ์ €์˜ ์„ ํƒ์„ ์ €์žฅํ•˜๋Š” ์Šคํ† ์–ด)

import { create } from 'zustand';

import { UserSelect } from '@/types';

type State = {
  userSelect: UserSelect;
};

type Action = {
  setUserSelectSize: (sizeId: number) => void;
  setUserSelectIngredientIds: (ingredientIds: number[]) => void;
  reset: () => void;
};

const initialState: State = {
  userSelect: {
    sizeId: 0,
    ingredientIds: [],
  },
};

export const useUserSelectStore = create<State & Action>()((set) => ({
  ...initialState,
  setUserSelectSize: (sizeId: number) =>
    set((state) => ({ userSelect: { ...state.userSelect, sizeId } })),
  setUserSelectIngredientIds: (ingredientIds: number[]) =>
    set((state) => ({ userSelect: { ...state.userSelect, ingredientIds } })),
  reset: () => set(initialState),
}));

์˜ˆ์ „์—” ๋Œ€์ถฉ ๊ณต์‹๋ฌธ์„œ ์ฝ๊ณ  ํ˜ผ์ž์„œ ์งฐ๋Š”๋ฐ, ๋‹ค์‹œ ๊ณต์‹๋ฌธ์„œ๋ฅผ ๊ผผ๊ผผํ•˜๊ฒŒ ๋ณด๋ฉด์„œ ์ข€๋” ํŽธํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ถ”ํ›„์— Immer์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์„œ ์ข€๋” ๊น”๋”ํ•˜๊ณ  ํŽธํ•˜๊ฒŒ ์งœ๋ด์•ผ๊ฒ ๋‹ค. ์ง€๊ธˆ state ์ •๋„์—์„œ๋Š” Immer๋ฅผ ๊ตณ์ด ์ ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๐Ÿ“ ํšŒ๊ณ 

๊ทธ๋ž˜๋„ ์˜ค๋Š˜๋„ ํŽ˜์ด์ง€ ํ•˜๋‚˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ๋๋‚ฌ๋‹ค. ์ ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๋˜ zustand๋„ ๋‚ด ๊ฐœ์ธ์ ์œผ๋ก  Next์™€ ์ž˜ ๋งž๋Š” ๋Š๋‚Œ์ด๋ผ ์žฌ๋ฏธ์žˆ๊ฒŒ ์ž˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ƒ๊ฐ๋ณด๋‹ค ์ด์ „์— ๊ตฌํ˜„ํ–ˆ๋˜ Carousel ์ชฝ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ•ด์„œ ์กฐ๊ธˆ ๊ท€์ฐฎ์•˜์ง€๋งŒโ€ฆ ์ผ๋‹จ์€ UX ์ ์œผ๋กœ๋Š” ๋ฌธ์ œ์—†์ด ์ž˜ ๋งˆ๋ฌด๋ฆฌํ•œ ๊ฒƒ ๊ฐ™๋‹ค!

์ฐธ๊ณ