React Custom Component (1) ๐Ÿ“

forhreverยท2023๋…„ 2์›” 21์ผ
0

๐Ÿ“ข UI ์ปดํฌ๋„ŒํŠธ์˜ ํ•„์š”์„ฑ

โ“ ๋ฌธ์ œ์ 

  • ํ”„๋กœ์ ํŠธ์˜ ์ƒํ™ฉ์—์„œ ์ ˆ๋Œ€์ ์œผ๋กœ ๋งŽ์€ ์ˆ˜์˜ ํ™”๋ฉด๊ณผ ๋ณต์žํ•œ ํ™”๋ฉด์ด ๋ฌธ์ œ์ด๋‹ค.
  • ๊ธฐ๋ณธ์ ์ธ ๋ ˆ์ด์•„์›ƒ ๊ตฌ์„ฑ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๋Š” UI๋“ค์€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์žฌ์‚ฌ์šฉ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ.

๐Ÿ’ก ์žฅ์ 

  • ์ ˆ๋Œ€์ ์ธ ์ฝ”๋“œ๋Ÿ‰์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„์ด ๋‹จ์ถ•๋œ๋‹ค.

๐Ÿ“ข ๋””์ž์ธ ์‹œ์Šคํ…œ

๋””์ž์ธ ์‹œ์Šคํ…œ์ด๋ž€ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉํ•œ ๊ณตํ†ต ์ปฌ๋Ÿฌ, ์„œ์ฒด, ์ธํ„ฐ๋ž™์…˜, ๊ฐ์ข… ์ •์ฑ… ๋ฐ ๊ทœ์ •์— ๊ด€ํ•œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •๋ฆฌํ•ด๋†“์€ ๊ฒƒ์ด๋ฉฐ ๋ถˆํ•„์š”ํ•œ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์„ ์—†์• ๊ธฐ ์œ„ํ•ด ์ฒด๊ณ„์ ์œผ๋กœ ์ •๋ฆฌํ•œ ์‹œ์Šคํ…œ์„ ๋งํ•œ๋‹ค.

  • ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์ด ์•„๋‹ˆ๋‹ค.
  • ์˜ค๋Š˜๋‚  ๋””์ž์ด๋„ˆ์™€ ๊ฐœ๋ฐœ์ž๋“ค์€ UI ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐํ™”๋ฅผ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ๋‹ค.
  • UI ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด๋ฃจ๋Š” ์กฐ๊ฐ๋“ค์˜ ์‹œ๊ฐ์ ์ด๊ณ  ๊ธฐ๋Šฅ์ ์ธ ์†์„ฑ์„ ์บก์Šํ™”ํ•œ๋‹ค.
  • ์ตœ๊ทผ์— ๋“ฑ์žฅํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋“ค์€ ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜๋ฐฑ๊ฐœ์˜ ๋ชจ๋“ˆ์‹ UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ฐฐ์—ด๋œ ๊ตฌ์กฐ๋ฅผ ์ด๋ฃจ๊ณ  ์žˆ๋‹ค.

๐Ÿ’ก ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ํŠน์ง•

  • ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ UI ์ปดํฌ๋„ŒํŠธ๋“ค๋กœ ์ด๋ฃจ์–ด์ ธ, ๋ณต์žกํ•˜๊ณ  ๊ฒฌ๊ณ ํ•˜๋ฉฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•˜๊ธฐ์— ์šฉ์ดํ•œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋””์ž์ด๋„ˆ์™€ ๊ฐœ์ž˜์ž ๋ชจ๋‘ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์—, ์„œ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.
  • ์กฐ์ง์˜ ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ '์ง„์‹ค์˜ ๊ทผ์›'์ด๊ธฐ๋„ ํ•œ๋‹ค.

๐Ÿ” ๋งŽ์€ ๊ธฐ์—…๋“ค์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” Tool
๐Ÿ“š ์Šคํ† ๋ฆฌ๋ถ(Storybook): UI ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ๊ณผ ์ž๋™์œผ๋กœ ๋ฌธ์„œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
โš›๏ธ ๋ฆฌ์•กํŠธ(React): ์„ ์–ธ ์ค‘์‹ฌ ์ปดํฌ๋„ŒํŠธ UI(create-react-app)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๐Ÿ’… ์Šคํƒ€์ผ ์ปดํฌ๋„ŒํŠธ(Styled-components): ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„์˜ ์Šคํƒ€์ผ๋ง์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
โœจ ํ”„๋ฆฌํ‹ฐ์–ด(Prettier): ์ž๋™ํ™”๋œ ์ฝ”๋“œ ํฌ๋งทํŒ…์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


๊ณผ์ œ - React Custom Component ๐Ÿ“

1. Modal

Modal CSS

  • Styled Components ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด ModalContainer ModalBackdrop ModalBtn ModalView ์ปดํฌ๋„ŒํŠธ์˜ CSS๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ModalContainer : Modal์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์ฃผ๋Š” ์ปจํ…Œ์ด๋„ˆ ์ปดํฌ๋„ŒํŠธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ModalBackdrop : Modal์ด ๋–ด์„ ๋•Œ์˜ ๋ฐฐ๊ฒฝ์„ ๊น”์•„์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ModalBtn : Modal ์ฐฝ์„ ํ‚ค๊ณ  ๋Œ ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ์ž…๋‹ˆ๋‹ค.
  • ModalView : Modal ์ฐฝ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.
  • ๊ตฌํ˜„ํ•œ Styled Components๋“ค์„ Modal ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

Modal ๋ฒ„ํŠผ ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • ModalBtn ์„ ํด๋ฆญํ•˜๋ฉด Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen)๋ฅผ boolean ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen์ด true์ธ ์ƒํƒœ)์ผ ๋•Œ๋งŒ ๋ชจ๋‹ฌ์ฐฝ๊ณผ ๋ฐฐ๊ฒฝ์ด ๋œฐ ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen์ด true์ธ ์ƒํƒœ)์ผ ๋•Œ๋Š” ModalBtn์˜ ๋‚ด๋ถ€ ํ…์ŠคํŠธ๊ฐ€ 'Opened!' ๋กœ Modal์ด ๋‹ซํžŒ ์ƒํƒœ(isOpen์ด false์ธ ์ƒํƒœ)์ผ ๋•Œ๋Š” ModalBtn ์˜ ๋‚ด๋ถ€ ํ…์ŠคํŠธ๊ฐ€ 'Open Modal'์ด ๋˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Modal ๋ฒ„ํŠผ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ฝ”๋“œ

export const Modal = () => {
  const [isOpen, setIsOpen] = useState(false);
  const openModalHandler = () => {
    // TODO : isOpen์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
    setIsOpen(!isOpen)
  };
  return (
    <>
      <ModalContainer onClick={openModalHandler}>  {/* ์ฐฝ๋ฐ– ํด๋ฆญํ•  ๊ฒฝ์šฐ Modal์ฐฝ ๋‹ซ๊ธฐ */}
        <ModalBtn
        // TODO : ํด๋ฆญํ•˜๋ฉด Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen)๋ฅผ boolean ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
        onClick={openModalHandler}
         >
          {isOpen ? 'Opened!' : 'OpenModal'}
          {/* TODO : ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen์ด true์ธ ์ƒํƒœ)์ผ ๋•Œ๋Š” ModalBtn์˜ ๋‚ด๋ถ€ ํ…์ŠคํŠธ๊ฐ€ 'Opened!' ๋กœ Modal์ด ๋‹ซํžŒ ์ƒํƒœ(isOpen์ด false์ธ ์ƒํƒœ)์ผ ๋•Œ๋Š” ModalBtn ์˜ ๋‚ด๋ถ€ ํ…์ŠคํŠธ๊ฐ€ 'Open Modal'์ด ๋˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. */}
         </ModalBtn> 
        {/* TODO : ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen์ด true์ธ ์ƒํƒœ)์ผ ๋•Œ๋งŒ ๋ชจ๋‹ฌ์ฐฝ๊ณผ ๋ฐฐ๊ฒฝ์ด ๋œฐ ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. */}
        {isOpen === false ? null : 
          <ModalBackdrop>
            <ModalView>
              <div className='desc'>๋ชจ๋‹ฌ ๋‚ด์šฉ์ด ๋ณด์—ฌ์ง‘๋‹ˆ๋‹ค.</div>
              <Exitbtn onClick = {openModalHandler}>ํ™•์ธ</Exitbtn>
            </ModalView>
          </ModalBackdrop>
        }
      </ModalContainer>
    </>
  );
};

2. Toggle

Toggle CSS

  • Styled Components ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด ToggleContainer Desc ์ปดํฌ๋„ŒํŠธ์˜ CSS๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ToggleContainer : Toggle์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์ฃผ๋Š” ์ปจํ…Œ์ด๋„ˆ ์ปดํฌ๋„ŒํŠธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • Desc : Toggle Switch์˜ ์ƒํƒœ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ํ…์ŠคํŠธ๋ฅผ ๋‹ด๋Š” ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.
  • ํ† ๊ธ€ ์Šค์œ„์น˜๊ฐ€ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์˜ฎ๊ฒจ์ง€๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š” CSS์˜ transition ์†์„ฑ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Toggle ๋ฒ„ํŠผ ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • ToggleContainer ๋‚ด๋ถ€์— .toggle-container .toggle-circle ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ง„ div ์š”์†Œ๋ฅผ ๊ฐ๊ฐ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒ์„ฑํ•œ ์š”์†Œ์— ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง์„ ํ™œ์šฉํ•ด Toggle Switch๊ฐ€ ON์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ์—๋งŒ toggle--checked ํด๋ž˜์Šค๋ฅผ ๋‘ ์š”์†Œ ๋ชจ๋‘์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ CSS์—์„œ๋Š” ํ…œํ”Œ๋ฆฟ ๋ฆฌํ„ฐ๋Ÿด๊ณผ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ํ™œ์šฉํ•ด ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
<div className={`toggle-container ${isOn ? "toggle--checked" : ""}`} />
  • ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด Toggle Switch๊ฐ€ ON์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ์— Desc ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ํ…์ŠคํŠธ๋ฅผ 'Toggle Switch ON' ์œผ๋กœ Toggle Switch๊ฐ€ OFF์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ์—๋Š” 'Toggle Switch OFF'๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

Toggle ๋ฒ„ํŠผ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ฝ”๋“œ

export const Toggle = () => {
  const [isOn, setisOn] = useState(false);
  const toggleHandler = () => {
    // TODO : isOn์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
    setisOn(!isOn)
  };
  return (
    <>
      <ToggleContainer
        // TODO : ํด๋ฆญํ•˜๋ฉด ํ† ๊ธ€์ด ์ผœ์ง„ ์ƒํƒœ(isOn)๋ฅผ boolean ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
        onClick={toggleHandler}
        >
        {/* TODO : ์•„๋ž˜์— div ์—˜๋ฆฌ๋จผํŠธ 2๊ฐœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค๋ฅผ 'toggle-container', 'toggle-circle' ๋กœ ์ง€์ •ํ•˜์„ธ์š”. */}
        {/* TIP : Toggle Switch๊ฐ€ ON์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ์—๋งŒ toggle--checked ํด๋ž˜์Šค๋ฅผ div ์—˜๋ฆฌ๋จผํŠธ 2๊ฐœ์— ๋ชจ๋‘ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง์„ ํ™œ์šฉํ•˜์„ธ์š”. */}
        <div className={`toggle-container ${isOn ? "toggle--checked" : null}`} />
        <div className={`toggle-circle ${isOn ? "toggle--checked" : null}`} />
      </ToggleContainer>
      {/* TODO : Desc ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ™œ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. */}
      {/* TIP:  Toggle Switch๊ฐ€ ON์ธ ์ƒํƒœ์ผ ๊ฒฝ์šฐ์— Desc ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ํ…์ŠคํŠธ๋ฅผ 'Toggle Switch ON'์œผ๋กœ, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ 'Toggle Switch OFF'๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•˜์„ธ์š”. */}
      {isOn === false ? 
      <Desc> <div className='switch--Off'>Toggle Switch OFF</div></Desc> :
      <Desc> <div className='switch--On'>Toggle Switch ON</div></Desc>
      }
    </>
  );
};

3. Tab

Tab CSS

  • Styled Components ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด TabMenu Desc ์ปดํฌ๋„ŒํŠธ์˜ CSS๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • TabMenu : Tab์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์ฃผ๋Š” ์ปจํ…Œ์ด๋„ˆ ์ปดํฌ๋„ŒํŠธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • Desc : Toggle Switch์˜ ์ƒํƒœ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ํ…์ŠคํŠธ๋ฅผ ๋‹ด๋Š” ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

Tab ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • TabMenu ๋‚ด๋ถ€์— .submenu ํด๋ž˜์Šค๋ช…์„ ๊ฐ€์ง„ li ์š”์†Œ๋“ค์„ map ์„ ์ด์šฉํ•œ ๋ฐ˜๋ณต์„ ํ†ตํ•ด ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • TabMenu ๋‚ด๋ถ€์— .submenu ํด๋ž˜์Šค๋ช…์„ ๊ฐ€์ง„ li ์š”์†Œ์˜ textContent ๋Š” ๊ฐ ์š”์†Œ์˜ name ์ž…๋‹ˆ๋‹ค.
  • ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Tab ๋ฉ”๋‰ด๊ฐ€ ์„ ํƒ๋œ ์ƒํƒœ์ผ ๋•Œ, ์„ ํƒ๋œ Tab ๋ฉ”๋‰ด li ์š”์†Œ์˜ ํด๋ž˜์Šค๋ช…๋งŒ submenu focused ๊ฐ€ ๋˜์–ด์•ผ ํ•˜๊ณ , ์„ ํƒ๋˜์ง€ ์•Š์€ ๋‚˜๋จธ์ง€๋Š”submenu ๊ฐ€ ๋˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • TabMenu ๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ˜„์žฌ ์„ ํƒ๋œ ํƒญ์˜ ์ธ๋ฑ์Šค ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์•„ currentTab ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” selectMenuHandler ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • TabMenu ๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ˜„์žฌ ์„ ํƒ๋œ ํƒญ ๋ฉ”๋‰ด๋งŒ .focused CSS๊ฐ€ ์ ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • TabMenu ๋ฅผ ํด๋ฆญํ•˜๋ฉด Desc ์ปดํฌ๋„ŒํŠธ์˜ content ์˜ ๋‚ด์šฉ์ด ํ•ด๋‹น ํƒญ์˜ content๋กœ ๋ฐ”๋€Œ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Tab ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ฝ”๋“œ

export const Tab = () => {
  // TIP: Tab Menu ์ค‘ ํ˜„์žฌ ์–ด๋–ค Tab์ด ์„ ํƒ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ
  // currentTab ์ƒํƒœ์™€ currentTab์„ ๊ฐฑ์‹ ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•˜๊ณ , ์ดˆ๊ธฐ๊ฐ’์€ 0 ์ž…๋‹ˆ๋‹ค.
  const [currentTab, setTab] = useState(0);
  const menuArr = [
    { name: 'Tab1', content: 'Tab menu ONE' },
    { name: 'Tab2', content: 'Tab menu TWO' },
    { name: 'Tab3', content: 'Tab menu THREE' },
  ];
  const selectMenuHandler = (index) => {
    // TIP: parameter๋กœ ํ˜„์žฌ ์„ ํƒํ•œ ์ธ๋ฑ์Šค ๊ฐ’์„ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋ฒคํŠธ ๊ฐ์ฒด(event)๋Š” ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค
    // TODO : ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋ฉด ํ˜„์žฌ ์„ ํƒ๋œ Tab Menu ๊ฐ€ ๊ฐฑ์‹ ๋˜๋„๋ก ํ•จ์ˆ˜๋ฅผ ์™„์„ฑํ•˜์„ธ์š”.
    setTab(index);
  };
  return (
    <>
      <div>
        <TabMenu>
          {/*TODO: ์•„๋ž˜ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋‚ด์šฉ ๋Œ€์‹ ์—, map์„ ์ด์šฉํ•œ ๋ฐ˜๋ณต์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.*/}
          {/*TIP: li ์—˜๋ฆฌ๋จผํŠธ์˜ class๋ช…์˜ ๊ฒฝ์šฐ ์„ ํƒ๋œ tab ์€ 'submenu focused' ๊ฐ€ ๋˜๋ฉฐ, 
                  ๋‚˜๋จธ์ง€ 2๊ฐœ์˜ tab์€ 'submenu' ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.*/}
          {/* <li className="submenu">{menuArr[0].name}</li>
          <li className="submenu">{menuArr[1].name}</li>
          <li className="submenu">{menuArr[2].name}</li> */}
          {menuArr.map( (tap, index) => {
            return (
              <li key = {index} className = {currentTab === index ? "submenu focused" : "submenu"}
                onClick = {() => selectMenuHandler(index)}>{tap.name}</li>
            )
          })}
        </TabMenu>
        <Desc>
          {/*TODO: ์•„๋ž˜ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋‚ด์šฉ ๋Œ€์‹ ์—, ํ˜„์žฌ ์„ ํƒ๋œ ๋ฉ”๋‰ด ๋”ฐ๋ฅธ content๋ฅผ ํ‘œ์‹œํ•˜์„ธ์š”*/}
          <p>{menuArr[currentTab].content}</p>
        </Desc>
      </div>
    </>
  );
};


์˜ค๋Š˜ ํ•™์Šต์„ ๋งˆ์น˜๊ณ  ๋‚˜์„œ, ๐Ÿ“–

์˜ค๋Š˜์€ ์ €๋ฒˆ์— ํ”ผ๊ทธ๋งˆ๋กœ ๋งŒ๋“ค์—ˆ๋˜ ๋ชจ๋‹ฌ, ํ† ๊ธ€, ํƒญ์„ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•ด ๋ณด๋Š” ๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•ž์„œ ๋ฐฐ์šด custom component๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ง„ํ–‰ํ•˜์˜€๋‹ค. ๋‚˜๋ฆ„ ํ• ๋งŒํ–ˆ๊ณ , css ๋ถ€๋ถ„์€ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„์—์„œ ์‚ด์ง ์‚๊ทธ๋•ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์•„์ง ๋ฒ ์–ด๋ฏธ๋‹ˆ์—„ 1๊ฐœ, ํƒœ๊ทธ ๊ตฌํ˜„๋„ ํ•˜์ง€ ์•Š์•˜๊ณ  css ๋ถ€๋ถ„์—์„œ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋Š” ๋ถ€๋ถ„๊ณผ ๊ฐ€์šด๋ฐ ์ •๋ ฌ์ด ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์œผ๋กœ ๋‚ด์ผ ๋งˆ๋ฌด๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.

profile
๊ฐœ๋ฐœ์ž ์„ฑ์žฅ ๊ณ„๋‹จ ์˜ฌ๋ผ๊ฐ€๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€