[๐ŸŽ์ฝ”๋”ฉ์• ํ”Œ ๊ฐ•์˜์š”์•ฝ]React์—์„œ props๋ฅผ ์‘์šฉํ•œ ์ƒ์„ธํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ ๐Ÿ“„

๐ŸŒˆ KJยท2025๋…„ 5์›” 17์ผ

codingapple

๋ชฉ๋ก ๋ณด๊ธฐ
10/23
post-thumbnail

๋™์  UI๋ฅผ ํ™œ์šฉํ•œ ์ƒ์„ธํŽ˜์ด์ง€ ๊ตฌํ˜„ ๐Ÿงฉ

์˜ค๋Š˜์˜ ๋ชฉํ‘œ ๐ŸŽฏ

  • ํด๋ฆญํ•œ ๊ธ€์˜ ์ œ๋ชฉ์ด ๋ชจ๋‹ฌ์ฐฝ์— ํ‘œ์‹œ๋˜๊ฒŒ ํ•˜๊ธฐ
  • 0๋ฒˆ ๊ธ€ ํด๋ฆญ โ†’ 0๋ฒˆ ๊ธ€์ œ๋ชฉ ํ‘œ์‹œ
  • 1๋ฒˆ ๊ธ€ ํด๋ฆญ โ†’ 1๋ฒˆ ๊ธ€์ œ๋ชฉ ํ‘œ์‹œ

๋™์  UI ์ œ์ž‘ 3๋‹จ๊ณ„ ๐Ÿ“

1. HTML/CSS๋กœ ๋ฏธ๋ฆฌ ๋””์ž์ธํ•˜๊ธฐ ๐ŸŽจ

  • ๋ชจ๋‹ฌ์ฐฝ์€ ์ด๋ฏธ ๋””์ž์ธ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ํŒจ์Šค โœ…

2. ํ˜„์žฌ UI ์ƒํƒœ๋ฅผ state๋กœ ๋งŒ๋“ค๊ธฐ ๐Ÿ’พ

let [title, setTitle] = useState(0);
  • ๋ชจ๋‹ฌ์ฐฝ์— ํ‘œ์‹œํ•  ๊ธ€ ๋ฒˆํ˜ธ๋ฅผ state๋กœ ๊ด€๋ฆฌ
  • ์ˆซ์žํ˜• state๋กœ ํ˜„์žฌ ๋ณด์—ฌ์ค„ ๊ธ€์˜ ์ธ๋ฑ์Šค ์ €์žฅ

3. state์— ๋”ฐ๋ผ UI ํ‘œ์‹œ ๋ฐฉ๋ฒ• ์ž‘์„ฑํ•˜๊ธฐ ๐Ÿ”„

function Modal(props) {
  return (
    <div className="modal">
      <h4>{ props.๊ธ€์ œ๋ชฉ[props.title] }</h4>
      <p>๋‚ ์งœ</p>
      <p>์ƒ์„ธ๋‚ด์šฉ</p>
    </div>
  )
}
  • props.๊ธ€์ œ๋ชฉ[title]๋กœ ํ˜„์žฌ ์„ ํƒ๋œ ์ธ๋ฑ์Šค์˜ ๊ธ€์ œ๋ชฉ ํ‘œ์‹œ
  • state ๊ฐ’์ด ๋ฐ”๋€Œ๋ฉด ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ ๊ธ€์ œ๋ชฉ์ด ์ž๋™์œผ๋กœ ํ‘œ์‹œ๋จ

ํด๋ฆญ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐํ•˜๊ธฐ ๐Ÿ–ฑ๏ธ

๊ธฐ๋ณธ ๋ฒ„์ „ (๋ฐ˜๋ณต๋ฌธ ์—†์ด) ๐Ÿ”ฐ

function App() {
  let [title, setTitle] = useState(0);
  return (
    <div>
      <button onClick={()=>{ setTitle(0) }}> 0๋ฒˆ๊ธ€ </button>
      <button onClick={()=>{ setTitle(1) }}> 1๋ฒˆ๊ธ€ </button>
      <button onClick={()=>{ setTitle(2) }}> 2๋ฒˆ๊ธ€ </button>
      <Modal ๊ธ€์ œ๋ชฉ={๊ธ€์ œ๋ชฉ} title={title} />
    </div>
  )
}
  • ๊ฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ•ด๋‹น ์ธ๋ฑ์Šค๋กœ state ๋ณ€๊ฒฝ
  • state๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ชจ๋‹ฌ์ฐฝ์˜ ๋‚ด์šฉ๋„ ์ž๋™ ์—…๋ฐ์ดํŠธ

map ํ•จ์ˆ˜ ํ™œ์šฉ ๋ฒ„์ „ ๐Ÿ”

function App() {
  let [๊ธ€์ œ๋ชฉ, ๊ธ€์ œ๋ชฉ๋ณ€๊ฒฝ] = useState(['๋‚จ์ž์ฝ”ํŠธ ์ถ”์ฒœ', '๊ฐ•๋‚จ ์šฐ๋™๋ง›์ง‘', 'ํŒŒ์ด์ฌ๋…ํ•™']);
  let [title, setTitle] = useState(0);
  return (
    <div>
      {
        ๊ธ€์ œ๋ชฉ.map(function(a, i) {
          return (
            <div className="list" key={i}>
              <h4 onClick={()=>{ setTitle(i) }}>{ ๊ธ€์ œ๋ชฉ[i] }</h4>
              <p>2์›” 18์ผ ๋ฐœํ–‰</p>
            </div>
          )
        })
      }
      <Modal ๊ธ€์ œ๋ชฉ={๊ธ€์ œ๋ชฉ} title={title} />
    </div>
  )
}
  • map ํ•จ์ˆ˜ ๋‚ด์—์„œ ๊ฐ ํ•ญ๋ชฉ ํด๋ฆญ ์‹œ ์ธ๋ฑ์Šค ์ „๋‹ฌ
  • onClick={()=>{ setTitle(i) }}๋กœ ํด๋ฆญํ•œ ๊ธ€์˜ ์ธ๋ฑ์Šค๋กœ state ์—…๋ฐ์ดํŠธ

์ตœ์ข… ๊ตฌํ˜„ ์ฝ”๋“œ ๐Ÿ

function App() {
  let [๊ธ€์ œ๋ชฉ, ๊ธ€์ œ๋ชฉ๋ณ€๊ฒฝ] = useState(['๋‚จ์ž์ฝ”ํŠธ ์ถ”์ฒœ', '๊ฐ•๋‚จ ์šฐ๋™๋ง›์ง‘', 'ํŒŒ์ด์ฌ๋…ํ•™']);
  let [title, setTitle] = useState(0);
  let [modal, setModal] = useState(false);
  
  return (
    <div>
      {
        ๊ธ€์ œ๋ชฉ.map(function(a, i) {
          return (
            <div className="list" key={i}>
              <h4 onClick={()=>{ setModal(true); setTitle(i); }}>{ ๊ธ€์ œ๋ชฉ[i] }</h4>
              <p>2์›” 18์ผ ๋ฐœํ–‰</p>
            </div>
          )
        })
      }
      
      {
        modal === true 
        ? <Modal ๊ธ€์ œ๋ชฉ={๊ธ€์ œ๋ชฉ} title={title} /> 
        : null
      }
    </div>
  )
}

function Modal(props) {
  return (
    <div className="modal">
      <h4>{ props.๊ธ€์ œ๋ชฉ[props.title] }</h4>
      <p>๋‚ ์งœ</p>
      <p>์ƒ์„ธ๋‚ด์šฉ</p>
    </div>
  )
}
  • ๋ชจ๋‹ฌ ํ‘œ์‹œ ์—ฌ๋ถ€์™€ ํ˜„์žฌ ์„ ํƒ๋œ ๊ธ€ ๋ฒˆํ˜ธ๋ฅผ ๋™์‹œ์— ๊ด€๋ฆฌ
  • ๊ธ€ ํด๋ฆญ ์‹œ ๋ชจ๋‹ฌ ํ‘œ์‹œ ๋ฐ ์„ ํƒ๋œ ๊ธ€ ๋ฒˆํ˜ธ ์—…๋ฐ์ดํŠธ

๊ฐ•์˜ ๋‚ด์šฉ ๊ฒ€ํ†  ๐Ÿ”

  1. state ์œ„์น˜์— ๋Œ€ํ•œ ์›์น™ ์„ค๋ช…: ๊ฐ•์˜์—์„œ๋Š” "state๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์ค‘ ์ตœ๊ณ  ๋ถ€๋ชจ์— ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค"๋Š” ์ค‘์š”ํ•œ ์›์น™์„ ์„ค๋ช…ํ–ˆ์œผ๋‚˜, ์ด๊ฒƒ์ด React์˜ "์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ(lifting state up)" ๊ฐœ๋…์ž„์„ ๋ช…์‹œํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๐Ÿ“ค

  2. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง ์ตœ์ ํ™” ๋ถ€์กฑ: ํด๋ฆญ ์ด๋ฒคํŠธ์—์„œ ๋‘ ๊ฐœ์˜ state๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹(setModal(true); setTitle(i))์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, ์ด๋Š” React์˜ ๋ Œ๋”๋ง ์ตœ์ ํ™” ๊ด€์ ์—์„œ ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ”„

  3. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋ฐฉ์‹: ๋ชจ๋‹ฌ ํ‘œ์‹œ๋ฅผ ์œ„ํ•ด ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, && ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ๋” ๊ฐ„๊ฒฐํ•œ ๋ฐฉ์‹๋„ ์†Œ๊ฐœํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ”€

์ถ”๊ฐ€ ์ •๋ณด ๋ฐ ํŒ ๐Ÿ’ก

์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ ์ตœ์ ํ™” ๐Ÿ—๏ธ

// ๊ธ€ ๋ชฉ๋ก์„ ๋ณ„๋„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌ
function BlogPost({๊ธ€์ œ๋ชฉ, index, onClick}) {
  return (
    <div className="list">
      <h4 onClick={onClick}>{๊ธ€์ œ๋ชฉ}</h4>
      <p>2์›” 18์ผ ๋ฐœํ–‰</p>
    </div>
  );
}

function App() {
  let [๊ธ€์ œ๋ชฉ, ๊ธ€์ œ๋ชฉ๋ณ€๊ฒฝ] = useState(['๋‚จ์ž์ฝ”ํŠธ ์ถ”์ฒœ', '๊ฐ•๋‚จ ์šฐ๋™๋ง›์ง‘', 'ํŒŒ์ด์ฌ๋…ํ•™']);
  let [title, setTitle] = useState(0);
  let [modal, setModal] = useState(false);
  
  return (
    <div>
      {๊ธ€์ œ๋ชฉ.map((์ œ๋ชฉ, i) => (
        <BlogPost 
          key={i} 
          ๊ธ€์ œ๋ชฉ={์ œ๋ชฉ} 
          index={i} 
          onClick={() => { 
            setModal(true); 
            setTitle(i); 
          }} 
        />
      ))}
      
      {modal && <Modal ๊ธ€์ œ๋ชฉ={๊ธ€์ œ๋ชฉ} title={title} />}
    </div>
  );
}
  • ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋” ์ž‘์€ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ ๐Ÿ”
  • && ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ๋” ๊ฐ„๊ฒฐํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์ ์šฉ โœ…

useCallback์„ ํ™œ์šฉํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ตœ์ ํ™” ๐Ÿš€

import { useState, useCallback } from 'react';

function App() {
  let [๊ธ€์ œ๋ชฉ, ๊ธ€์ œ๋ชฉ๋ณ€๊ฒฝ] = useState(['๋‚จ์ž์ฝ”ํŠธ ์ถ”์ฒœ', '๊ฐ•๋‚จ ์šฐ๋™๋ง›์ง‘', 'ํŒŒ์ด์ฌ๋…ํ•™']);
  let [title, setTitle] = useState(0);
  let [modal, setModal] = useState(false);
  
  // ํด๋ฆญ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ตœ์ ํ™”
  const handleTitleClick = useCallback((i) => {
    setModal(true);
    setTitle(i);
  }, []);
  
  return (
    <div>
      {๊ธ€์ œ๋ชฉ.map((์ œ๋ชฉ, i) => (
        <div className="list" key={i}>
          <h4 onClick={() => handleTitleClick(i)}>{์ œ๋ชฉ}</h4>
          <p>2์›” 18์ผ ๋ฐœํ–‰</p>
        </div>
      ))}
      
      {modal && <Modal ๊ธ€์ œ๋ชฉ={๊ธ€์ œ๋ชฉ} title={title} />}
    </div>
  );
}
  • useCallback์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ํ•จ์ˆ˜ ์žฌ์ƒ์„ฑ ๋ฐฉ์ง€ ๐Ÿ”„
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”์— ๋„์›€์ด ๋˜๋ฉฐ ํŠนํžˆ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์ฃผ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ ์œ ์šฉ โšก

Context API๋ฅผ ํ™œ์šฉํ•œ ๋Œ€์•ˆ ๐ŸŒ

import { createContext, useState, useContext } from 'react';

// Context ์ƒ์„ฑ
const BlogContext = createContext();

function App() {
  let [๊ธ€์ œ๋ชฉ, ๊ธ€์ œ๋ชฉ๋ณ€๊ฒฝ] = useState(['๋‚จ์ž์ฝ”ํŠธ ์ถ”์ฒœ', '๊ฐ•๋‚จ ์šฐ๋™๋ง›์ง‘', 'ํŒŒ์ด์ฌ๋…ํ•™']);
  let [title, setTitle] = useState(0);
  let [modal, setModal] = useState(false);
  
  return (
    <BlogContext.Provider value={{ ๊ธ€์ œ๋ชฉ, title, setTitle, modal, setModal }}>
      <div>
        {๊ธ€์ œ๋ชฉ.map((์ œ๋ชฉ, i) => (
          <div className="list" key={i}>
            <h4 onClick={() => { 
              setModal(true); 
              setTitle(i); 
            }}>{์ œ๋ชฉ}</h4>
            <p>2์›” 18์ผ ๋ฐœํ–‰</p>
          </div>
        ))}
        
        {modal && <ModalWithContext />}
      </div>
    </BlogContext.Provider>
  );
}

function ModalWithContext() {
  const { ๊ธ€์ œ๋ชฉ, title } = useContext(BlogContext);
  
  return (
    <div className="modal">
      <h4>{๊ธ€์ œ๋ชฉ[title]}</h4>
      <p>๋‚ ์งœ</p>
      <p>์ƒ์„ธ๋‚ด์šฉ</p>
    </div>
  );
}
  • Context API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด props ์ „๋‹ฌ ์—†์ด๋„ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ state ๊ณต์œ  ๊ฐ€๋Šฅ ๐Ÿ”„
  • ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๊ฐ€ ๊นŠ์–ด์งˆ ๋•Œ props drilling ๋ฌธ์ œ ํ•ด๊ฒฐ์— ์œ ์šฉ ๐ŸŒณ

JavaScript && ์—ฐ์‚ฐ์ž์— ๋Œ€ํ•œ ์„ค๋ช…

&&๋Š” ๋…ผ๋ฆฌ AND ์—ฐ์‚ฐ์ž๋กœ, ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ์šฉ๋„๊ฐ€ ์žˆ์Œ.

1๏ธโƒฃ ๊ธฐ๋ณธ ๋…ผ๋ฆฌ ์—ฐ์‚ฐ (Boolean)

true && true    // true
true && false   // false
false && true   // false
false && false  // false

2๏ธโƒฃ ๋‹จ์ถ• ํ‰๊ฐ€ (Short-circuit Evaluation)

ํ•ต์‹ฌ: ์™ผ์ชฝ์ด false๋ฉด ์˜ค๋ฅธ์ชฝ์„ ์‹คํ–‰ํ•˜์ง€ ์•Š์Œ

let a = 5;
let b = 10;
a > 10 && console.log("์‹คํ–‰๋จ");     // ์ถœ๋ ฅ ์•ˆ๋จ (a > 10์ด false)
a < 10 && console.log("์‹คํ–‰๋จ");     // "์‹คํ–‰๋จ" ์ถœ๋ ฅ (a < 10์ด true)

3๏ธโƒฃ React์—์„œ์˜ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง โญ

๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ํŒจํ„ด:

function App() {
  let [๋ชจ๋‹ฌ์—ด๋ฆผ, ๋ชจ๋‹ฌ์—ด๋ฆผ๋ณ€๊ฒฝ] = useState(false);
  
  return (
    <div>
      <button onClick={() => ๋ชจ๋‹ฌ์—ด๋ฆผ๋ณ€๊ฒฝ(true)}>๋ชจ๋‹ฌ ์—ด๊ธฐ</button>
      
      {/* ๋ชจ๋‹ฌ์—ด๋ฆผ์ด true์ผ ๋•Œ๋งŒ Modal ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง */}
      {๋ชจ๋‹ฌ์—ด๋ฆผ && <Modal></Modal>}
    </div>
  );
}

๐Ÿ” ๋™์ž‘ ์›๋ฆฌ

{๋ชจ๋‹ฌ์—ด๋ฆผ && <Modal></Modal>}

๊ฒฝ์šฐ 1: ๋ชจ๋‹ฌ์—ด๋ฆผ์ด true์ผ ๋•Œ

  • true && <Modal></Modal> โ†’ <Modal></Modal> ๋ฐ˜ํ™˜ (์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง)

๊ฒฝ์šฐ 2: ๋ชจ๋‹ฌ์—ด๋ฆผ์ด false์ผ ๋•Œ

  • false && <Modal></Modal> โ†’ false ๋ฐ˜ํ™˜ (์•„๋ฌด๊ฒƒ๋„ ๋ Œ๋”๋ง ์•ˆ๋จ)

๐Ÿ“ ์‹ค์šฉ์ ์ธ ์˜ˆ์‹œ๋“ค

// ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ฅธ ๋ Œ๋”๋ง
{๋กœ๊ทธ์ธ๋จ && <div>ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!</div>}

// ๋ฐฐ์—ด์— ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ๋ Œ๋”๋ง
{๋ฐ์ดํ„ฐ.length > 0 && <List data={๋ฐ์ดํ„ฐ} />}

// ์—๋Ÿฌ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
{์—๋Ÿฌ && <div className="error">{์—๋Ÿฌ}</div>}

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

// ์ˆซ์ž 0์€ falsy์ด๋ฏ€๋กœ ์ฃผ์˜!
{items.length && <List />}  // items.length๊ฐ€ 0์ด๋ฉด 0์ด ํ™”๋ฉด์— ์ถœ๋ ฅ๋จ

// ํ•ด๊ฒฐ๋ฐฉ๋ฒ•
{items.length > 0 && <List />}  // ๋ช…์‹œ์ ์œผ๋กœ boolean ๋งŒ๋“ค๊ธฐ

React์—์„œ &&๋Š” "์กฐ๊ฑด์ด ์ฐธ์ผ ๋•Œ๋งŒ ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ๋‹ค"๋Š” ์ƒํ™ฉ์—์„œ ๊ฐ€์žฅ ์œ ์šฉํ•จ!

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