React 2์ฃผ์ฐจ ์ •๋ฆฌ

์ด ๊ธ€์˜ ๋ชฉ์ฐจ80๊ฐœ
  1. โœ… ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์˜ ์‚ฌ์šฉ
  2. ๐Ÿ” ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋ฐฉ์‹
  3. 1. if ๋ฌธ ์‚ฌ์šฉ
  4. 2. ์‚ผํ•ญ ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ (Inline ์กฐ๊ฑด)
  5. 3. && ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ
  6. โ— ์ฃผ์˜์‚ฌํ•ญ: false, null, undefined๋Š” ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Œ
  7. โœจ ์˜ˆ์ œ: ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์ „ํ™˜
  8. โญ๏ธ ์š”์•ฝ
  9. โœ… ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง์ด๋ž€?
  10. ๐Ÿ“Œ ์˜ˆ์ œ: ๋ฐฐ์—ด์„ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๊ธฐ
  11. ๐Ÿ” Key๋ž€?
  12. โ— key์— index๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋ ๊นŒ?
  13. โญ๏ธ ์š”์•ฝ
  14. โœ… ์™œ Controlled Component๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?
  15. โœ๏ธ Controlled Component ๊ธฐ๋ณธ ์˜ˆ์ œ
  16. โœ… ๋‹ค์–‘ํ•œ Form ์š”์†Œ๋“ค ์ œ์–ดํ•˜๊ธฐ
  17. ๐Ÿ“Œ textarea ์ œ์–ด
  18. ๐Ÿ“Œ select ์ œ์–ด
  19. โ— ์ฃผ์˜ํ•  ์ 
  20. โœ… ์‚ฌ์šฉ์ž ์ •๋ณด ์ž…๋ ฅ๋ฐ›๊ธฐ ์˜ˆ์ œ
  21. โญ๏ธ ์š”์•ฝ
  22. โœ… ์™œ ์ƒํƒœ ๊ณต์œ (State Lifting)๋ฅผ ํ• ๊นŒ?
  23. ๐Ÿ” ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ: ๋‘ input์˜ ๋™๊ธฐํ™”
  24. โญ๏ธ ํ•ต์‹ฌ ์ •๋ฆฌ
  25. โœ… ์–ธ์ œ ์ƒํƒœ๋ฅผ ๋Œ์–ด์˜ฌ๋ฆด๊นŒ?
  26. โœ… React๋Š” ์ƒ์†๋ณด๋‹ค ํ•ฉ์„ฑ์„ ๊ถŒ์žฅ
  27. ๐Ÿ”— ์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์˜ ์ข…๋ฅ˜
  28. 1. Containment (์ปจํ…Œ์ธ๋จผํŠธ: ์ž์‹ ํฌํ•จ)
  29. 2. Specialization (ํŠน์ˆ˜ํ™”: ์ผ๋ถ€ ๋‚ด์šฉ๋งŒ ๋ณ€๊ฒฝ)
  30. โญ๏ธ ํ•ฉ์„ฑ๊ณผ ์ƒ์† ๋น„๊ต
  31. โœ… ์–ธ์ œ Context๋ฅผ ์จ์•ผ ํ• ๊นŒ?
  32. ๐Ÿงช ๊ฐ„๋‹จํ•œ Context ์‚ฌ์šฉ ์˜ˆ์‹œ
  33. 1. Context ์ƒ์„ฑํ•˜๊ธฐ
  34. 2. Context ์ œ๊ณตํ•˜๊ธฐ (Provider)
  35. 3. Context ์‚ฌ์šฉํ•˜๊ธฐ (Consumer ๋˜๋Š” Hook)
  36. โšก ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ: useContext Hook
  37. ๐Ÿ” Context ํ๋ฆ„ ์š”์•ฝ
  38. โš ๏ธ Context ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ 
  39. โœจ ์–ธ์ œ Context๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„๊นŒ?
  40. โœ… CSS ๊ธฐ๋ณธ ๋ฌธ๋ฒ•
  41. ์˜ˆ์‹œ:
  42. ๐Ÿ“Œ ์„ ํƒ์ž(Selector) ์ข…๋ฅ˜
  43. 1๏ธโƒฃ ํƒœ๊ทธ ์„ ํƒ์ž (Element Selector)
  44. 2๏ธโƒฃ ํด๋ž˜์Šค ์„ ํƒ์ž (Class Selector)
  45. 3๏ธโƒฃ ID ์„ ํƒ์ž (ID Selector)
  46. 4๏ธโƒฃ ๊ทธ๋ฃน ์„ ํƒ์ž (Grouping Selector)
  47. 5๏ธโƒฃ ์ „์ฒด ์„ ํƒ์ž (Universal Selector)
  48. 6๏ธโƒฃ ๊ฒฐํ•ฉ ์„ ํƒ์ž (์กฐํ•ฉ)
  49. ๐ŸŽฏ ์ƒํƒœ ์„ ํƒ์ž (Pseudo-class)
  50. โœ… ํ…์ŠคํŠธ ๊ด€๋ จ ์†์„ฑ ์˜ˆ์‹œ
  51. โœ… ๋ฐ•์Šค ๋ชจ๋ธ ๊ด€๋ จ ์†์„ฑ ์˜ˆ์‹œ
  52. ๐Ÿ’ก ์ •๋ฆฌ
  53. โœ… 1. display
  54. ์ž์ฃผ ์“ฐ์ด๋Š” ๊ฐ’
  55. โœ… 2. visibility
  56. โœ… 3. position
  57. ์˜ˆ์‹œ:
  58. โœ… 4. width, height
  59. โœ… 5. margin, padding
  60. ๋ฐฉํ–ฅ๋ณ„ ์†์„ฑ
  61. โœ… 6. Flexbox ๊ธฐ์ดˆ
  62. ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์†์„ฑ
  63. ์˜ˆ์‹œ:
  64. โญ๏ธ ์ •๋ฆฌ
  65. โœ… ๊ธฐ๋ณธ ๊ตฌ์กฐ
  66. ๐Ÿ” ์ฃผ์š” ์šฉ์–ด ์ •๋ฆฌ
  67. ๐Ÿงญ 1. flex-direction
  68. ๐Ÿ“ 2. justify-content
  69. ๐Ÿงฒ 3. align-items
  70. ๐Ÿ”‚ 4. flex-wrap
  71. ๐Ÿ”ง 5. align-content
  72. ๐ŸŽš 6. ๊ฐœ๋ณ„ ์•„์ดํ…œ ์ •๋ ฌ - align-self
  73. ๐Ÿงช Flex ์†์„ฑ ์˜ˆ์ œ
  74. ๐Ÿ’ก Flex ์•„์ดํ…œ ์ „์šฉ ์†์„ฑ
  75. โญ๏ธ ์ •๋ฆฌ
  76. โœจ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
  77. ๐ŸŽฏ props๋กœ ์Šคํƒ€์ผ ๋™์  ์ œ์–ด
  78. ๐Ÿ“Œ ์Šคํƒ€์ผ ํ™•์žฅํ•˜๊ธฐ
  79. ๐Ÿ“ ์ „์—ญ ์Šคํƒ€์ผ ์„ค์ • - createGlobalStyle
  80. โญ๏ธ ์ •๋ฆฌ

๐Ÿ’ก ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง (Conditional Rendering)

๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ UI๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์„ โ€œ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋งโ€์ด๋ผ๊ณ  ํ•œ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” JavaScript์˜ ์กฐ๊ฑด๋ฌธ์„ ํ™œ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ๋ Œ๋”๋งํ•  ๋‚ด์šฉ์„ ๋™์ ์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.


โœ… ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์˜ ์‚ฌ์šฉ

React์—์„œ๋Š” ๋งˆ์น˜ if๋ฌธ์ฒ˜๋Ÿผ ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋‚˜ JSX ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ํ™”๋ฉด์— โ€œํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!โ€ ๋˜๋Š” โ€œ๋กœ๊ทธ์ธ ํ•ด์ฃผ์„ธ์š”โ€๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ” ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ๋ฐฉ์‹

1. if ๋ฌธ ์‚ฌ์šฉ

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;

  if (isLoggedIn) {
    return <h1>ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!</h1>;
  }
  return <h1>๋กœ๊ทธ์ธ ํ•ด์ฃผ์„ธ์š”.</h1>;
}
  • ๊ฐ€์žฅ ์ง๊ด€์ ์ธ ๋ฐฉ์‹์œผ๋กœ, ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์—ฌ๋Ÿฌ ์กฐ๊ฑด์ด ๋ณต์žกํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋…์„ฑ์ด ์ข‹๋‹ค.

2. ์‚ผํ•ญ ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ (Inline ์กฐ๊ฑด)

function Greeting(props) {
  return (
    <h1>
      {props.isLoggedIn ? 'ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!' : '๋กœ๊ทธ์ธ ํ•ด์ฃผ์„ธ์š”.'}
    </h1>
  );
}
  • ๊ฐ„๋‹จํ•œ ์กฐ๊ฑด์ผ ๊ฒฝ์šฐ ์งง๊ณ  ๊น”๋”ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • JSX ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ํŠน์ง•

3. && ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;

  return (
    <div>
      <h1>์•ˆ๋…•ํ•˜์„ธ์š”!</h1>
      {unreadMessages.length > 0 && (
        <h2>์ฝ์ง€ ์•Š์€ ๋ฉ”์‹œ์ง€: {unreadMessages.length}๊ฐœ</h2>
      )}
    </div>
  );
}
  • ํŠน์ • ์กฐ๊ฑด์ด true์ผ ๋•Œ๋งŒ JSX๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • unreadMessages.length > 0์ด ์ฐธ์ด๋ฉด <h2>๊ฐ€ ๋ Œ๋”๋ง๋œ๋‹ค.

โ— ์ฃผ์˜์‚ฌํ•ญ: false, null, undefined๋Š” ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Œ

return <div>{false}</div>; // ํ™”๋ฉด์— ์•„๋ฌด๊ฒƒ๋„ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Œ
  • JSX์—์„œ๋Š” false, null, undefined, true๋Š” ๋ฌด์‹œ๋˜๊ณ  ํ™”๋ฉด์— ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค..

โœจ ์˜ˆ์ œ: ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์ „ํ™˜

function LoginButton(props) {
  return <button onClick={props.onClick}>๋กœ๊ทธ์ธ</button>;
}

function LogoutButton(props) {
  return <button onClick={props.onClick}>๋กœ๊ทธ์•„์›ƒ</button>;
}

function LoginControl() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleClick = () => {
    setIsLoggedIn(!isLoggedIn);
  };

  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={handleClick} />
      ) : (
        <LoginButton onClick={handleClick} />
      )}
    </div>
  );
}
  • ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค **์ƒํƒœ(State)**๊ฐ€ ๋ฐ”๋€Œ๊ณ ,
  • ๊ทธ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์กฐ๊ฑด๋ถ€๋กœ ๋ Œ๋”๋ง๋œ๋‹ค.

โญ๏ธ ์š”์•ฝ

๋ฐฉ์‹ ์„ค๋ช… ํŠน์ง•
if ๋ฌธ JSX ๋ฐ”๊นฅ์—์„œ ์กฐ๊ฑด์„ ๋ถ„๊ธฐ ๋ณต์žกํ•œ ์กฐ๊ฑด์— ์ ํ•ฉ
์‚ผํ•ญ ์—ฐ์‚ฐ์ž JSX ์•ˆ์—์„œ ์กฐ๊ฑด ๋ถ„๊ธฐ ๊ฐ„๋‹จํ•œ ์กฐ๊ฑด ์ฒ˜๋ฆฌ
&& ์—ฐ์‚ฐ์ž true์ผ ๋•Œ๋งŒ ๋ Œ๋”๋ง ์กฐ๊ฑด๋ถ€ ์ถœ๋ ฅ์— ๊ฐ„ํŽธ

โœ๏ธ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ํ•„์ˆ˜ ๊ธฐ๋Šฅ



๐Ÿ’ก ๋ฆฌ์ŠคํŠธ์™€ Key

๋ฆฌ์•กํŠธ์—์„œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋•Œ, ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ

์ด๋•Œ ๊ฐ ํ•ญ๋ชฉ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ ๊ณ ์œ ํ•œ Key๊ฐ€ ํ•„์š”


โœ… ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง์ด๋ž€?

JavaScript์˜ map() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ์•ˆ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“Œ ์˜ˆ์ œ: ๋ฐฐ์—ด์„ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๊ธฐ

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) =>
  <li>{number}</li>
);

return <ul>{listItems}</ul>;

map()์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ์š”์†Œ๋“ค์„ li๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค, JSX๋กœ ์ถœ๋ ฅ


๐Ÿ” Key๋ž€?

๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ํ•ญ๋ชฉ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ์œ ํ•œ ๊ฐ’

๋ฆฌ์•กํŠธ๋Š” ์–ด๋–ค ํ•ญ๋ชฉ์ด ๋ณ€๊ฒฝ, ์ถ”๊ฐ€, ์‚ญ์ œ๋˜์—ˆ๋Š”์ง€ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด Key๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) =>
  <li key={number}>{number}</li>
);
  • ์—ฌ๊ธฐ์„œ key={number}๋Š” ๊ฐ ํ•ญ๋ชฉ์„ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ’
  • Key๊ฐ€ ์—†๊ฑฐ๋‚˜ ์ค‘๋ณต๋˜๋ฉด ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๊ณ  ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค.

โ— key์— index๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋ ๊นŒ?

const listItems = items.map((item, index) =>
  <li key={index}>{item}</li>
);
  • key๋กœ index๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค. โŒ
  • ์ด์œ : ๋ฆฌ์ŠคํŠธ์˜ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๊ฑฐ๋‚˜ ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€/์‚ญ์ œ๋˜๋ฉด index ๊ฐ’์ด ๋ฐ”๋€Œ์–ด ์ž˜๋ชป๋œ ๋™๊ธฐํ™”๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์—” ๊ณ ์œ  ID๊ฐ’์„ key๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.


โญ๏ธ ์š”์•ฝ

๊ฐœ๋… ์„ค๋ช…
๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง map() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐ˜๋ณต ๋ Œ๋”๋ง
key ๊ฐ ํ•ญ๋ชฉ์„ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ’
์ข‹์€ key ๊ฐ’ ๊ณ ์œ ํ•œ ID (index๋Š” ์ง€์–‘)

๐Ÿ’ก Form๊ณผ Controlled Component

์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” HTML ์š”์†Œ์ธ Form,

๊ทธ๋ฆฌ๊ณ  ์ž…๋ ฅ๊ฐ’์„ ๋ฆฌ์•กํŠธ์—์„œ ์ง์ ‘ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์„ Controlled Component๋ผ๊ณ  ํ•œ๋‹ค.


โœ… ์™œ Controlled Component๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

๊ธฐ์กด HTML์—์„œ๋Š” <input>, <textarea>, <select> ๋“ฑ form ์š”์†Œ๋“ค์ด DOM์ด ์ง์ ‘ ๊ด€๋ฆฌํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ƒํƒœ(state)๋ฅผ ํ†ตํ•ด ์ž…๋ ฅ๊ฐ’์„ ์ œ์–ด(์ œ์–ด๋œ ์ปดํฌ๋„ŒํŠธ) ํ•˜๋ฉด์„œ

์ž…๋ ฅ๋œ ๊ฐ’์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถ”์ ํ•˜๊ณ , ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋™์ž‘์„ ์œ ์—ฐํ•˜๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.


โœ๏ธ Controlled Component ๊ธฐ๋ณธ ์˜ˆ์ œ

import { useState } from "react";

function NameForm() {
  const [name, setName] = useState("");

  const handleChange = (e) => {
    setName(e.target.value); // ์ž…๋ ฅ๊ฐ’์„ ์ƒํƒœ์— ์ €์žฅ
  };

  const handleSubmit = (e) => {
    e.preventDefault(); // ๊ธฐ๋ณธ ๋™์ž‘(ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ) ๋ง‰๊ธฐ
    alert(`์ž…๋ ฅํ•œ ์ด๋ฆ„: ${name}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={name} onChange={handleChange} />
      <button type="submit">์ œ์ถœ</button>
    </form>
  );
}
  • value={name}: input์˜ ๊ฐ’์„ ์ƒํƒœ์™€ ์—ฐ๊ฒฐ
  • onChange={handleChange}: ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ์ƒํƒœ ๊ฐฑ์‹ 
  • useState๋ฅผ ํ†ตํ•ด ์ž…๋ ฅ๊ฐ’์„ ์ œ์–ด (Controlled)

โœ… ๋‹ค์–‘ํ•œ Form ์š”์†Œ๋“ค ์ œ์–ดํ•˜๊ธฐ

๐Ÿ“Œ textarea ์ œ์–ด

<textarea value={message} onChange={(e) => setMessage(e.target.value)} />

๐Ÿ“Œ select ์ œ์–ด

<select value={selectedOption} onChange={(e) => setSelectedOption(e.target.value)}>
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
</select>
  • select์˜ value๋„ ์ƒํƒœ์™€ ์—ฐ๊ฒฐ
  • ๋‹ค์–‘ํ•œ ์ž…๋ ฅ ์š”์†Œ๋ฅผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ œ์–ด ๊ฐ€๋Šฅ

โ— ์ฃผ์˜ํ•  ์ 

  • input์— value๋ฅผ ์ง€์ •ํ–ˆ๋Š”๋ฐ onChange๋ฅผ ๋น ๋œจ๋ฆฌ๋ฉด ์ž…๋ ฅ ๋ถˆ๊ฐ€๋Šฅํ•œ ํ•„๋“œ๊ฐ€ ๋œ๋‹ค.
  • ํ•ญ์ƒ value์™€ onChange๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โœ… ์‚ฌ์šฉ์ž ์ •๋ณด ์ž…๋ ฅ๋ฐ›๊ธฐ ์˜ˆ์ œ

function UserForm() {
  const [userInfo, setUserInfo] = useState({ name: "", email: "" });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setUserInfo((prev) => ({
      ...prev,
      [name]: value,
    }));
  };

  return (
    <form>
      <input name="name" value={userInfo.name} onChange={handleChange} />
      <input name="email" value={userInfo.email} onChange={handleChange} />
    </form>
  );
}
  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ input์„ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ƒํƒœ ๊ด€๋ฆฌ
  • name ์†์„ฑ์„ ํ†ตํ•ด ์–ด๋–ค ํ•„๋“œ์ธ์ง€ ๊ตฌ๋ถ„

โญ๏ธ ์š”์•ฝ

๊ฐœ๋… ์„ค๋ช…
Controlled Component ๋ฆฌ์•กํŠธ ์ƒํƒœ๊ฐ€ form ์š”์†Œ์˜ ๊ฐ’์„ ์ œ์–ด
value ์ƒํƒœ ๊ฐ’์„ input ๋“ฑ์— ์—ฐ๊ฒฐ
onChange ์ž…๋ ฅ ๋ณ€ํ™” ์‹œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
์žฅ์  ์ž…๋ ฅ๊ฐ’ ์ถ”์ , ์กฐ๊ฑด ์ œ์–ด, ์‹ค์‹œ๊ฐ„ ๊ฒ€์ฆ ๊ฐ€๋Šฅ

๐Ÿ’ก ์ƒํƒœ ๊ณต์œ  (State Lifting)

์ƒํƒœ ๊ณต์œ ๋ž€, ์—ฌ๋Ÿฌ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋™์ผํ•œ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ,

๊ทธ ์ƒํƒœ๋ฅผ ๊ณตํ†ต์˜ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฌ๋ ค์„œ(lift up) ๊ด€๋ฆฌํ•˜๋Š” ํŒจํ„ด


โœ… ์™œ ์ƒํƒœ ๊ณต์œ (State Lifting)๋ฅผ ํ• ๊นŒ?

React์—์„œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋…๋ฆฝ์ ์ธ ์ƒํƒœ(state) ๋ฅผ ๊ฐ€์ง„๋‹ค.

ํ•˜์ง€๋งŒ ๋•Œ๋กœ๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.

์ด๋•Œ ์ƒํƒœ๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ๊ฐ๊ฐ์— ๋งŒ๋“ค๋ฉด โŒ ๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜ ๋ฐœ์ƒ

โ†’ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ์ƒํƒœ๋ฅผ ๊ณตํ†ต ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ์–ด์˜ฌ๋ฆผ


๐Ÿ” ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ: ๋‘ input์˜ ๋™๊ธฐํ™”

function TemperatureInput({ temperature, onTemperatureChange }) {
  return (
    <fieldset>
      <inputvalue={temperature}
        onChange={(e) => onTemperatureChange(e.target.value)}
      />
    </fieldset>
  );
}
function Calculator() {
  const [temperature, setTemperature] = useState("");

  return (
    <div>
      <TemperatureInputtemperature={temperature}
        onTemperatureChange={setTemperature}
      />
      <TemperatureInputtemperature={temperature}
        onTemperatureChange={setTemperature}
      />
    </div>
  );
}
  • Calculator ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ ,
  • TemperatureInput์€ ์ƒํƒœ๋ฅผ props๋กœ ๋ฐ›์•„์„œ ํ‘œ์‹œ & ์ˆ˜์ •ํ•จ
  • ์ด๋ ‡๊ฒŒ ์ƒํƒœ๋ฅผ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์˜ฌ๋ฆฌ๋Š” ๊ฒƒ์„ State Lifting์ด๋ผ๊ณ  ํ•จ

โญ๏ธ ํ•ต์‹ฌ ์ •๋ฆฌ

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

โœ… ์–ธ์ œ ์ƒํƒœ๋ฅผ ๋Œ์–ด์˜ฌ๋ฆด๊นŒ?

  • 2๊ฐœ ์ด์ƒ์˜ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•  ๋•Œ
  • ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋ผ๋ฆฌ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•  ๋•Œ
  • ์˜ˆ: ํ•„ํ„ฐ๋ง๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ์™€ ๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ์ฐฝ

  • SearchInput: ๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ
  • List: ํ•„ํ„ฐ๋ง๋œ ๊ฒฐ๊ณผ ํ‘œ์‹œ
  • ๊ณตํ†ต๋œ ์ƒํƒœ filterText๋Š” ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ FilterableList์—์„œ ๊ด€๋ฆฌ

๐Ÿ’ก ์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ๊ณผ ์ƒ์†

React์—์„œ๋Š” ํ•ฉ์„ฑ(Composition) ์„ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•˜๊ณ ,

์ƒ์†(Inheritance) ๋ณด๋‹ค๋Š” ํ•ฉ์„ฑ์„ ์šฐ์„ ์ ์œผ๋กœ ์‚ฌ์šฉ


โœ… React๋Š” ์ƒ์†๋ณด๋‹ค ํ•ฉ์„ฑ์„ ๊ถŒ์žฅ

  • ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด์—์„œ๋Š” ์ƒ์†์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€๋งŒ,

    React์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋ฅผ ์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํ•ฉ์„ฑ์€ ๋” ์œ ์—ฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ ๋†’์€ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ”— ์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์˜ ์ข…๋ฅ˜

React์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ํ•ฉ์„ฑ ํŒจํ„ด์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

1. Containment (์ปจํ…Œ์ธ๋จผํŠธ: ์ž์‹ ํฌํ•จ)

์ž์‹ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ props.children์œผ๋กœ ๋ฐ›์•„์„œ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ์‹

function Card({ children }) {
  return <div className="card">{children}</div>;
}
<Card>
  <h2>๊ณต์ง€์‚ฌํ•ญ</h2>
  <p>์ด๋ฒˆ ์ฃผ ๊ธˆ์š”์ผ์€ ํœด๊ฐ•์ž…๋‹ˆ๋‹ค.</p>
</Card>

โœ… props.children์„ ํ™œ์šฉํ•˜๋ฉด,

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹์œผ๋กœ ์–ด๋–ค ์š”์†Œ๋“  ์ž์œ ๋กญ๊ฒŒ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋‹ค.


2. Specialization (ํŠน์ˆ˜ํ™”: ์ผ๋ถ€ ๋‚ด์šฉ๋งŒ ๋ณ€๊ฒฝ)

์ผ๋ฐ˜์ ์ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํŠน์ • ์šฉ๋„์— ๋งž๊ฒŒ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

function Dialog({ title, message }) {
  return (
    <div className="dialog">
      <h1>{title}</h1>
      <p>{message}</p>
    </div>
  );
}

function WelcomeDialog() {
  return <Dialog title="ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!" message="์ €ํฌ ์‚ฌ์ดํŠธ์— ์˜ค์‹  ๊ฑธ ํ™˜์˜ํ•ด์š”." />;
}

โœ… ์ผ๋ฐ˜์ ์ธ ๊ตฌ์กฐ๋Š” ์œ ์ง€ํ•˜๋ฉด์„œ,

๋‚ด์šฉ๋งŒ ๋ฐ”๊พธ๊ณ  ์‹ถ์„ ๋•Œ ์ ํ•ฉํ•œ ๋ฐฉ์‹


โญ๏ธ ํ•ฉ์„ฑ๊ณผ ์ƒ์† ๋น„๊ต

ํ•ญ๋ชฉ ํ•ฉ์„ฑ(Composition) ์ƒ์†(Inheritance)
์‚ฌ์šฉ์„ฑ React์—์„œ ๊ถŒ์žฅ โœ… ๊ฑฐ์˜ ์‚ฌ์šฉ ์•ˆ ํ•จ โŒ
์žฅ์  ์œ ์—ฐํ•˜๊ณ  ์กฐ๋ฆฝ ๊ฐ€๋Šฅ ์ฝ”๋“œ ๊ฒฐํ•ฉ๋„ ๋†’์Œ
์˜ˆ์‹œ children, props extends ํด๋ž˜์Šค ์ƒ์† ๋“ฑ

๐Ÿ’ก Context API๋ž€?

Context๋Š” ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์ „์ฒด์— ๋ฐ์ดํ„ฐ(์ƒํƒœ)๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฆฌ์•กํŠธ ๊ธฐ๋Šฅ

React๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค.

์ฆ‰, ๋ถ€๋ชจ โ†’ ์ž์‹์œผ๋กœ props๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ

ํ•˜์ง€๋งŒ, ์ปดํฌ๋„ŒํŠธ ๊นŠ์ด๊ฐ€ ๊นŠ์–ด์ง€๋ฉด

๋งค๋ฒˆ props๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๋ฒˆ๊ฑฐ๋กญ๊ณ  ๋น„ํšจ์œจ์ ์ด๋‹ค.

โ†’ ์ด๋Ÿด ๋•Œ ๋“ฑ์žฅํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ Context API


โœ… ์–ธ์ œ Context๋ฅผ ์จ์•ผ ํ• ๊นŒ?

์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•  ๋•Œ

์˜ˆ๋ฅผ ๋“ค๋ฉด ์ด๋Ÿฐ ๋ฐ์ดํ„ฐ๋“ค:

  • ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ •๋ณด (user)
  • ํ˜„์žฌ UI ํ…Œ๋งˆ (dark / light)
  • ์„ ํƒ๋œ ์–ธ์–ด (locale)
  • ์‚ฌ์ดํŠธ ์„ค์ • ๊ฐ’ ๋“ฑโ€ฆ

๐Ÿงช ๊ฐ„๋‹จํ•œ Context ์‚ฌ์šฉ ์˜ˆ์‹œ

1. Context ์ƒ์„ฑํ•˜๊ธฐ

import React from "react";

// ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ "light"๋ฅผ ์„ค์ •
const ThemeContext = React.createContext("light");

2. Context ์ œ๊ณตํ•˜๊ธฐ (Provider)

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

value๋กœ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๊ณต์œ ํ•  ๊ฐ’์„ ๋„˜๊ฒจ์ค€๋‹ค.

3. Context ์‚ฌ์šฉํ•˜๊ธฐ (Consumer ๋˜๋Š” Hook)

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {(theme) => <button className={theme}>๋ฒ„ํŠผ</button>}
    </ThemeContext.Consumer>
  );
}

โšก ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ: useContext Hook

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” useContext()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ๊ฐ„๋‹จํ•ด์š”!

import { useContext } from "react";

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>๋ฒ„ํŠผ</button>;
}

๐Ÿ” Context ํ๋ฆ„ ์š”์•ฝ

  1. React.createContext()๋กœ ์ƒ์„ฑ
  2. Provider๋กœ ๋ฐ์ดํ„ฐ ์ œ๊ณต
  3. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ useContext() ๋˜๋Š” Consumer๋กœ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ

โš ๏ธ Context ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ 

์ฃผ์˜ํ•  ์  ์„ค๋ช…
๋ฆฌ๋ Œ๋”๋ง ์ฃผ์˜ Context์˜ value๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ์ „๋ถ€ ๋ฆฌ๋ Œ๋”๋ง
๊ณผ๋„ํ•œ ์‚ฌ์šฉ โŒ ๋ชจ๋“  ์ƒํƒœ๋ฅผ Context๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ์˜คํžˆ๋ ค ๋ณต์žกํ•ด์ง
props๋กœ ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ ๋‹จ์ˆœํ•œ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด๋ฉด props๊ฐ€ ๋” ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ์Œ

โœจ ์–ธ์ œ Context๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„๊นŒ?

  • ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด (user)
  • ํ…Œ๋งˆ ์ •๋ณด (๋‹คํฌ๋ชจ๋“œ, ๋ผ์ดํŠธ๋ชจ๋“œ)
  • ์–ธ์–ด ์„ค์ •
  • ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํƒœ (e-commerce)

๐ŸŽจ CSS ๊ธฐ๋ณธ ๋ฌธ๋ฒ•๊ณผ ์…€๋ ‰ํ„ฐ

CSS๋Š” ์›น์‚ฌ์ดํŠธ๋ฅผ ๊พธ๋ฏธ๋Š” ์–ธ์–ด

HTML๋กœ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ , CSS๋กœ ์ƒ‰๊น”, ํฌ๊ธฐ, ๋ฐฐ์น˜, ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.


โœ… CSS ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

์„ ํƒ์ž {
  ์†์„ฑ: ๊ฐ’;
}

์˜ˆ์‹œ:

h1 {
  color: blue;
  font-size: 24px;
}
  • ์„ ํƒ์ž(selector): ์–ด๋–ค HTML ์š”์†Œ์— ์Šคํƒ€์ผ์„ ์ ์šฉํ• ์ง€ ์„ ํƒ
  • ์†์„ฑ(property): ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ์Šคํƒ€์ผ ํ•ญ๋ชฉ (ex. ์ƒ‰์ƒ, ๊ธ€์”จ ํฌ๊ธฐ ๋“ฑ)
  • ๊ฐ’(value): ์†์„ฑ์— ์ ์šฉํ•  ๊ตฌ์ฒด์ ์ธ ๊ฐ’

๐Ÿ“Œ ์„ ํƒ์ž(Selector) ์ข…๋ฅ˜

1๏ธโƒฃ ํƒœ๊ทธ ์„ ํƒ์ž (Element Selector)

h1 {
  color: green;
}

โ†’ ๋ชจ๋“  <h1> ํƒœ๊ทธ์— ์ ์šฉ


2๏ธโƒฃ ํด๋ž˜์Šค ์„ ํƒ์ž (Class Selector)

.title {
  font-weight: bold;
}

โ†’ class ์†์„ฑ์ด "title"์ธ ์š”์†Œ์— ์ ์šฉ

์‚ฌ์šฉ ์‹œ HTML์— class ์ด๋ฆ„์„ ๋ถ€์—ฌํ•ด์•ผ ํ•จ

<p class="title">์ค‘์š”ํ•œ ๋ฌธ์žฅ</p>

3๏ธโƒฃ ID ์„ ํƒ์ž (ID Selector)

#main {
  background-color: yellow;
}

โ†’ id ์†์„ฑ์ด "main"์ธ ์š”์†Œ์— ์ ์šฉ

์ฃผ์˜: ID๋Š” ํ•œ ํŽ˜์ด์ง€์— ํ•˜๋‚˜๋งŒ

<div id="main">๋‚ด์šฉ</div>

4๏ธโƒฃ ๊ทธ๋ฃน ์„ ํƒ์ž (Grouping Selector)

h1, h2, p {
  margin: 0;
}

โ†’ ์—ฌ๋Ÿฌ ํƒœ๊ทธ์— ๊ฐ™์€ ์Šคํƒ€์ผ์„ ํ•œ ๋ฒˆ์— ์ ์šฉ


5๏ธโƒฃ ์ „์ฒด ์„ ํƒ์ž (Universal Selector)

* {
  box-sizing: border-box;
}

โ†’ ๋ชจ๋“  ์š”์†Œ์— ์ ์šฉ

์ดˆ๊ธฐํ™”๋‚˜ ๊ณตํ†ต ์Šคํƒ€์ผ ์„ค์ • ์‹œ ์œ ์šฉ


6๏ธโƒฃ ๊ฒฐํ•ฉ ์„ ํƒ์ž (์กฐํ•ฉ)

div.title {
  color: red;
}

โ†’ div ํƒœ๊ทธ ์ค‘์— class๊ฐ€ "title"์ธ ์š”์†Œ์—๋งŒ ์ ์šฉ

#main .title {
  font-size: 18px;
}

โ†’ id๊ฐ€ "main"์ธ ์š”์†Œ ๋‚ด๋ถ€์˜ class "title" ์š”์†Œ์— ์ ์šฉ


๐ŸŽฏ ์ƒํƒœ ์„ ํƒ์ž (Pseudo-class)

์—˜๋ฆฌ๋จผํŠธ์˜ ํŠน์ • ์ƒํƒœ์— ๋”ฐ๋ผ ์Šคํƒ€์ผ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์„ ํƒ์ž ์„ค๋ช…
:hover ๋งˆ์šฐ์Šค ์˜ค๋ฒ„ ์‹œ
:active ํด๋ฆญ ์ค‘์ผ ๋•Œ
:focus ํฌ์ปค์Šค(์ž…๋ ฅ์ฐฝ ์„ ํƒ) ์ƒํƒœ
:first-child ๋ถ€๋ชจ์˜ ์ฒซ ๋ฒˆ์งธ ์ž์‹ ์š”์†Œ
:last-child ๋ถ€๋ชจ์˜ ๋งˆ์ง€๋ง‰ ์ž์‹ ์š”์†Œ
button:hover {
  background-color: skyblue;
}

โœ… ํ…์ŠคํŠธ ๊ด€๋ จ ์†์„ฑ ์˜ˆ์‹œ

p {
  font-size: 16px;
  color: #333;
  text-align: center;
}

โœ… ๋ฐ•์Šค ๋ชจ๋ธ ๊ด€๋ จ ์†์„ฑ ์˜ˆ์‹œ

.box {
  width: 100px;
  height: 100px;
  padding: 10px;
  border: 1px solid black;
  margin: 20px;
}

๐Ÿ’ก ์ •๋ฆฌ

์š”์†Œ ์„ค๋ช…
์„ ํƒ์ž ์Šคํƒ€์ผ ์ ์šฉ ๋Œ€์ƒ์„ ์ง€์ •
์†์„ฑ ์–ด๋–ค ์Šคํƒ€์ผ์„ ์ค„์ง€ ์ง€์ •
๊ฐ’ ๊ตฌ์ฒด์ ์ธ ์Šคํƒ€์ผ ๊ฐ’ ์„ค์ •

๐Ÿ“ CSS ๋ ˆ์ด์•„์›ƒ ๊ด€๋ จ ์†์„ฑ ์ •๋ฆฌ

CSS ๋ ˆ์ด์•„์›ƒ ์†์„ฑ์€ ์›น ํŽ˜์ด์ง€์˜ ๊ตฌ์กฐ์™€ ์š”์†Œ๋“ค์˜ ๋ฐฐ์น˜ ์œ„์น˜๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

ํ•œ๋ˆˆ์— ๋ณด๊ธฐ ์‰ฝ๊ณ , ๊ตฌ์กฐ๊ฐ€ ๊น”๋”ํ•œ ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํ•ต์‹ฌ ๋„๊ตฌ


โœ… 1. display

์š”์†Œ์˜ ํ‘œ์‹œ ๋ฐฉ์‹์„ ์ง€์ •ํ•˜๋Š” ์†์„ฑ

์ž์ฃผ ์“ฐ์ด๋Š” ๊ฐ’

๊ฐ’ ์„ค๋ช…
block ๋ธ”๋ก ์š”์†Œ. ํ•œ ์ค„ ์ „์ฒด๋ฅผ ์ฐจ์ง€ํ•จ (div, p, h1 ๋“ฑ ๊ธฐ๋ณธ๊ฐ’)
inline ์ธ๋ผ์ธ ์š”์†Œ. ์ฝ˜ํ…์ธ  ํฌ๊ธฐ๋งŒํผ๋งŒ ๊ณต๊ฐ„ ์ฐจ์ง€ (span, a ๋“ฑ ๊ธฐ๋ณธ๊ฐ’)
none ์š”์†Œ๋ฅผ ์ˆจ๊น€ (ํ™”๋ฉด๊ณผ DOM์—์„œ ์‚ฌ๋ผ์ง)
flex Flexbox ๋ ˆ์ด์•„์›ƒ ์ปจํ…Œ์ด๋„ˆ๋กœ ์„ค์ •
inline-block ์ธ๋ผ์ธ์ฒ˜๋Ÿผ ๋ฐฐ์น˜๋˜์ง€๋งŒ ๋ธ”๋ก์ฒ˜๋Ÿผ width, height ์กฐ์ ˆ ๊ฐ€๋Šฅ
.container {
  display: flex;
}

โœ… 2. visibility

์š”์†Œ๋ฅผ ์ˆจ๊ธธ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•˜์ง€๋งŒ, ๊ณต๊ฐ„์€ ์œ ์ง€๋จ

๊ฐ’ ์„ค๋ช…
visible ๊ธฐ๋ณธ๊ฐ’. ๋ณด์ž„
hidden ๋ณด์ด์ง€ ์•Š์Œ. ํ•˜์ง€๋งŒ ํ•ด๋‹น ์˜์—ญ์€ ์ฐจ์ง€
.box {
  visibility: hidden;
}

โœ… 3. position

์š”์†Œ๋ฅผ ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ์œ„์น˜์‹œํ‚ฌ์ง€ ์„ค์ •ํ•˜๋Š” ์†์„ฑ

๊ฐ’ ์„ค๋ช…
static ๊ธฐ๋ณธ๊ฐ’. ๋ฌธ์„œ ํ๋ฆ„์— ๋”ฐ๋ฆ„
relative ํ˜„์žฌ ์œ„์น˜ ๊ธฐ์ค€์œผ๋กœ ์ด๋™ ๊ฐ€๋Šฅ
absolute ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด position ์ง€์ •๋œ ์กฐ์ƒ ๊ธฐ์ค€์œผ๋กœ ์œ„์น˜
fixed ๋ธŒ๋ผ์šฐ์ € ์ฐฝ ๊ธฐ์ค€์œผ๋กœ ๊ณ ์ •
sticky ์Šคํฌ๋กค ์œ„์น˜์— ๋”ฐ๋ผ ๊ณ ์ •/ํ•ด์ œ ์ „ํ™˜

์˜ˆ์‹œ:

.box {
  position: absolute;
  top: 50px;
  left: 100px;
}

โœ… 4. width, height

์š”์†Œ์˜ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ์†์„ฑ

.box {
  width: 300px;
  height: 150px;
}
  • auto : ์ฝ˜ํ…์ธ ์— ๋”ฐ๋ผ ์ž๋™ ์กฐ์ ˆ
  • % : ๋ถ€๋ชจ ์š”์†Œ์˜ ํฌ๊ธฐ์— ๋Œ€ํ•œ ๋ฐฑ๋ถ„์œจ
  • min-width, max-width : ์ตœ์†Œ/์ตœ๋Œ€ ํฌ๊ธฐ ์ œํ•œ

โœ… 5. margin, padding

์š”์†Œ ๋ฐ– ์—ฌ๋ฐฑ(margin) ๊ณผ ์•ˆ์ชฝ ์—ฌ๋ฐฑ(padding)

.box {
  margin: 20px;
  padding: 10px;
}

๋ฐฉํ–ฅ๋ณ„ ์†์„ฑ

์†์„ฑ ์„ค๋ช…
margin-top, padding-top ์œ„์ชฝ ์—ฌ๋ฐฑ
margin-right, padding-right ์˜ค๋ฅธ์ชฝ ์—ฌ๋ฐฑ
margin-bottom, padding-bottom ์•„๋ž˜์ชฝ ์—ฌ๋ฐฑ
margin-left, padding-left ์™ผ์ชฝ ์—ฌ๋ฐฑ

โœ… 6. Flexbox ๊ธฐ์ดˆ

Flexbox(ํ”Œ๋ ‰์Šค ๋ฐ•์Šค) ๋Š” ๋ณต์žกํ•œ ๋ ˆ์ด์•„์›ƒ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” CSS3์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ

.container {
  display: flex;
}

์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์†์„ฑ

์†์„ฑ ์„ค๋ช…
flex-direction ์•„์ดํ…œ ์ •๋ ฌ ๋ฐฉํ–ฅ (row, column, row-reverse, column-reverse)
justify-content ์ฃผ ์ถ•(Main axis) ์ •๋ ฌ (start, center, space-between, โ€ฆ)
align-items ๊ต์ฐจ ์ถ•(Cross axis) ์ •๋ ฌ (start, center, stretch, โ€ฆ)

์˜ˆ์‹œ:

.container {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

โญ๏ธ ์ •๋ฆฌ

  • display: ์š”์†Œ์˜ ๊ธฐ๋ณธ ํ‘œ์‹œ ์œ ํ˜• ๊ฒฐ์ •
  • position: ํ™”๋ฉด์—์„œ ์š”์†Œ์˜ ์ •ํ™•ํ•œ ์œ„์น˜ ์กฐ์ •
  • margin, padding: ์—ฌ๋ฐฑ ์กฐ์ •
  • flex: ๋‹ค์–‘ํ•œ ๋ ˆ์ด์•„์›ƒ์„ ์‰ฝ๊ฒŒ ๊ตฌ์„ฑ
  • width, height: ํฌ๊ธฐ ์„ค์ •

๐Ÿ“ฆ Flexbox๋ž€?

Flexbox(Flexible Box Layout) ๋Š” CSS์—์„œ 1์ฐจ์› ๋ ˆ์ด์•„์›ƒ์„ ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ

  • ๋ณต์žกํ•œ ๋ ˆ์ด์•„์›ƒ์„ ๋‹จ์ˆœํ•œ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  • ์š”์†Œ๋“ค์„ ํ–‰(row) ๋˜๋Š” ์—ด(column) ๋ฐฉํ–ฅ์œผ๋กœ ์ •๋ ฌํ•˜๊ธฐ์— ์ ํ•ฉ

โœ… ๊ธฐ๋ณธ ๊ตฌ์กฐ

Flexbox๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ๋จผ์ € ๋ถ€๋ชจ ์š”์†Œ์— display: flex ๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.

.container {
  display: flex;
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด .container๋Š” Flex Container, ๋‚ด๋ถ€ ์š”์†Œ๋“ค์€ Flex Item์ด ๋œ๋‹ค.


๐Ÿ” ์ฃผ์š” ์šฉ์–ด ์ •๋ฆฌ

์šฉ์–ด ์„ค๋ช…
Main Axis ์ฃผ ์ถ• (๊ธฐ๋ณธ์€ ์ˆ˜ํ‰)
Cross Axis ๊ต์ฐจ ์ถ• (๊ธฐ๋ณธ์€ ์ˆ˜์ง)
Flex Container display: flex๊ฐ€ ์„ค์ •๋œ ๋ถ€๋ชจ ์š”์†Œ
Flex Item ์ปจํ…Œ์ด๋„ˆ ์•ˆ์— ์žˆ๋Š” ์ž์‹ ์š”์†Œ๋“ค

๐Ÿงญ 1. flex-direction

์•„์ดํ…œ์˜ ๋ฐฐ์น˜ ๋ฐฉํ–ฅ์„ ์ง€์ •ํ•œ๋‹ค.

๊ฐ’ ์„ค๋ช…
row โ†’ ์ˆ˜ํ‰ (๊ธฐ๋ณธ๊ฐ’)
row-reverse โ† ์ˆ˜ํ‰ ์—ญ์ˆœ
column โ†“ ์ˆ˜์ง
column-reverse โ†‘ ์ˆ˜์ง ์—ญ์ˆœ
.container {
  display: flex;
  flex-direction: row; /* ๋˜๋Š” column */
}

๐Ÿ“ 2. justify-content

Main Axis(์ฃผ ์ถ•) ๊ธฐ์ค€ ์ •๋ ฌ

๊ฐ’ ์„ค๋ช…
flex-start ์‹œ์ž‘์  ์ •๋ ฌ
flex-end ๋์  ์ •๋ ฌ
center ์ค‘์•™ ์ •๋ ฌ
space-between ์–‘ ๋ ์ •๋ ฌ + ์•„์ดํ…œ ์‚ฌ์ด ๋™์ผ ๊ฐ„๊ฒฉ
space-around ์•„์ดํ…œ ์–‘์ชฝ์— ๋™์ผ ๊ฐ„๊ฒฉ
space-evenly ์•„์ดํ…œ ์‚ฌ์ด์‚ฌ์ด ํฌํ•จํ•œ ๊ฐ„๊ฒฉ์ด ๋™์ผ
.container {
  justify-content: center;
}

๐Ÿงฒ 3. align-items

Cross Axis(๊ต์ฐจ ์ถ•) ๊ธฐ์ค€ ์ •๋ ฌ (ํ•œ ์ค„์ผ ๋•Œ)

๊ฐ’ ์„ค๋ช…
stretch (๊ธฐ๋ณธ๊ฐ’) ์•„์ดํ…œ์„ ์ปจํ…Œ์ด๋„ˆ์— ๊ฝ‰ ์ฐจ๊ฒŒ ๋Š˜๋ฆผ
flex-start ์‹œ์ž‘์  ์ •๋ ฌ
flex-end ๋์  ์ •๋ ฌ
center ์ค‘์•™ ์ •๋ ฌ
baseline ํ…์ŠคํŠธ ๊ธฐ์ค€์„  ์ •๋ ฌ
.container {
  align-items: stretch;
}

๐Ÿ”‚ 4. flex-wrap

์•„์ดํ…œ์ด ๋„˜์น  ๊ฒฝ์šฐ ์ค„๋ฐ”๊ฟˆ ์—ฌ๋ถ€๋ฅผ ์„ค์ •

๊ฐ’ ์„ค๋ช…
nowrap ์ค„๋ฐ”๊ฟˆ ์•ˆ ํ•จ (๊ธฐ๋ณธ๊ฐ’)
wrap ์ž๋™ ์ค„๋ฐ”๊ฟˆ
wrap-reverse ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ์ค„๋ฐ”๊ฟˆ
.container {
  flex-wrap: wrap;
}

๐Ÿ”ง 5. align-content

์—ฌ๋Ÿฌ ์ค„์ผ ๊ฒฝ์šฐ, ์ค„ ์ „์ฒด์— ๋Œ€ํ•œ ๊ต์ฐจ์ถ• ์ •๋ ฌ ๋ฐฉ์‹ ์ง€์ •

.container {
  align-content: space-between;
}

align-items๋Š” โ€œ์•„์ดํ…œโ€ ์ •๋ ฌ์ด๊ณ 

align-content๋Š” โ€œ์ค„ ์ „์ฒดโ€ ์ •๋ ฌ


๐ŸŽš 6. ๊ฐœ๋ณ„ ์•„์ดํ…œ ์ •๋ ฌ - align-self

ํŠน์ • ์•„์ดํ…œ๋งŒ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ต์ฐจ์ถ• ์ •๋ ฌ์„ ์กฐ์ •ํ•  ๋•Œ ์‚ฌ์šฉ

.item {
  align-self: flex-end;
}

๐Ÿงช Flex ์†์„ฑ ์˜ˆ์ œ

.container {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
}
<div class="container">
  <div class="item">Box 1</div>
  <div class="item">Box 2</div>
  <div class="item">Box 3</div>
</div>

๐Ÿ’ก Flex ์•„์ดํ…œ ์ „์šฉ ์†์„ฑ

์†์„ฑ ์„ค๋ช…
flex-grow ๋‚จ์€ ๊ณต๊ฐ„์„ ์–ผ๋งˆ๋‚˜ ํ™•์žฅํ• ์ง€
flex-shrink ๊ณต๊ฐ„ ๋ถ€์กฑ ์‹œ ์ค„์–ด๋“œ๋Š” ๋น„์œจ
flex-basis ์•„์ดํ…œ์˜ ๊ธฐ๋ณธ ํฌ๊ธฐ
.item {
  flex: 1; /* flex-grow: 1, shrink: 1, basis: 0 */
}

โญ๏ธ ์ •๋ฆฌ

  • Flexbox๋Š” ์š”์†Œ์˜ ์ •๋ ฌ๊ณผ ๋ฐฐ์น˜๋ฅผ ํ•œ ์ฐจ์›์—์„œ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ
  • ์ถ• ๊ฐœ๋…(Main / Cross)์ดํ•ด ํ•„์š”


๐Ÿ–ผ๏ธ styled-components๋ž€?

styled-components๋Š” CSS-in-JS ๋ฐฉ์‹์˜ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

JavaScript ํŒŒ์ผ ์•ˆ์—์„œ CSS๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ด๋ฅผ ์ปดํฌ๋„ŒํŠธ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ

  • React์™€ ๋งค์šฐ ์ž˜ ์–ด์šธ๋ฆฌ๋Š” ์Šคํƒ€์ผ๋ง ๋ฐฉ์‹
  • ์ฝ”๋“œ์™€ ์Šคํƒ€์ผ์ด ํ•จ๊ป˜ ์žˆ์œผ๋ฏ€๋กœ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ด

โœจ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

import styled from 'styled-components';

const Title = styled.h1`
  color: #fff;
  background: #333;
  padding: 20px;
  border-radius: 8px;
`;

function App() {
  return <Title>Hello, styled-components!</Title>;
}
  • styled.h1 โ†’ HTML ํƒœ๊ทธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์Šคํƒ€์ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑ
  • ๋ฐฑํ‹ฑ(```) ์•ˆ์— CSS ๋ฌธ๋ฒ• ๊ทธ๋Œ€๋กœ ์ž‘์„ฑ

๐ŸŽฏ props๋กœ ์Šคํƒ€์ผ ๋™์  ์ œ์–ด

styled-components๋Š” props๋ฅผ ํ™œ์šฉํ•ด ์Šคํƒ€์ผ๋„ ๋™์ ์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

const Button = styled.button`
  background: ${(props) => (props.primary ? "blue" : "gray")};
  color: white;
  padding: 10px 20px;
  border: none;
`;

function App() {
  return (
    <><Button>Default</Button>
      <Button primary>Primary</Button>
    </>
  );
}
  • props.primary ๊ฐ’์— ๋”ฐ๋ผ ๋ฒ„ํŠผ ์ƒ‰์ƒ์ด ๋ฐ”๋€œ
  • ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง์„ JS ๋กœ์ง์ฒ˜๋Ÿผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿ“Œ ์Šคํƒ€์ผ ํ™•์žฅํ•˜๊ธฐ

๊ธฐ์กด ์Šคํƒ€์ผ๋“œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ์‚ฌ์šฉ ๋ฐ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const Button = styled.button`
  padding: 10px;
  background: #ccc;
`;

const RoundButton = styled(Button)`
  border-radius: 20px;
`;
  • RoundButton์€ Button์˜ ์Šคํƒ€์ผ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ™•์žฅ
  • ๊ณตํ†ต ์Šคํƒ€์ผ์„ ๋ถ„๋ฆฌํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉ

๐Ÿ“ ์ „์—ญ ์Šคํƒ€์ผ ์„ค์ • - createGlobalStyle

import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    background: #f5f5f5;
    font-family: 'Noto Sans KR', sans-serif;
  }
`;

function App() {
  return (
    <><GlobalStyle />
      <Main />
    </>
  );
}
  • GlobalStyle์„ ํ†ตํ•ด ์ „์ฒด ์•ฑ์— ๊ณตํ†ต ์Šคํƒ€์ผ ์ ์šฉ ๊ฐ€๋Šฅ
  • App ์ปดํฌ๋„ŒํŠธ ๋ฃจํŠธ์—์„œ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ

โญ๏ธ ์ •๋ฆฌ

์žฅ์  ์„ค๋ช…
์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ๋„ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
CSS ๋ฌธ๋ฒ• ๊ทธ๋Œ€๋กœ ๋”ฐ๋กœ ๋ฌธ๋ฒ•์„ ๋ฐฐ์šธ ํ•„์š” ์—†์Œ
props ํ™œ์šฉ ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง ๊ฐ€๋Šฅ
JS์™€์˜ ํ†ตํ•ฉ ๋™์  ๋กœ์ง ๊ตฌํ˜„ ๊ฐ€๋Šฅ
์ „์ฒด ๊ธ€ ๋ณด๊ธฐ