25.06.05 - se5ri/React GitHub Wiki

ch02-start

vite

09/
β”œβ”€β”€ node_modules/
β”œβ”€β”€ public/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ ~/likelion-script/script_js/React/works/
β”‚   β”‚   └── Title.tsx
β”‚   └── pages/
β”‚       └── todo/
β”‚           └── List.tsx
β”‚   β”œβ”€β”€ App.css
β”‚   β”œβ”€β”€ App.tsx
β”‚   β”œβ”€β”€ index.css
β”‚   β”œβ”€β”€ main.tsx
β”‚   └── vite-env.d.ts
β”œβ”€β”€ .gitignore
β”œβ”€β”€ eslint.config.js
β”œβ”€β”€ index.html
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ README.md
β”œβ”€β”€ tsconfig.app.json
β”œβ”€β”€ tsconfig.json
└── tsconfig.node.json

πŸ“œ 09 Vite둜 개발 ν™˜κ²½ ꡬ좕 및 λΉŒλ“œ, 배포

JSX

  • κ°œλ…

    4. JSX

    4.1 JSXλž€?

    • JSX(JavaScript XML)λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 파일 내에 HTMLκ³Ό μœ μ‚¬ν•œ λ§ˆν¬μ—…μ„ μž‘μ„±ν•  수 있게 ν•΄μ£ΌλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ ν™•μž₯ ꡬ문
    • Reactμ—μ„œ μ‚¬μš©ν•  λͺ©μ μœΌλ‘œ κ°œλ°œλ˜κΈ°λŠ” ν–ˆμ§€λ§Œ JSXκ°€ React에 ν¬ν•¨λœ κΈ°μˆ μ€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— Reactμ—μ„œ JSX μ‚¬μš©μ΄ ν•„μˆ˜λŠ” μ•„λ‹˜
      • React.createElement() 직접 μ‚¬μš©

    4.2 JSX κ·œμΉ™

    1 단일 루트 μš”μ†Œλ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•œλ‹€.

    • JSXλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 객체둜 λ³€ν™˜λ˜λŠ”λ° ν•¨μˆ˜κ°€ μ—¬λŸ¬ 객체λ₯Ό λ°˜ν™˜ ν•  수 μ—†μœΌλ―€λ‘œ 단일 객체λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ 해야함

    • λ§Œμ•½ 단일 μš”μ†Œλ₯Ό λ°˜ν™˜ν•˜μ§€ μ•Šμ„ 경우 Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? μ—λŸ¬ λ°œμƒ

      return (
        <h1>Todo List</h1>
        <div>...</div>
      );
    • 루트 μš”μ†Œλ₯Ό μΆ”κ°€

      return (
        <div>
          <h1>Todo List</h1>
          <div>...</div>
        </div>
      );
    • Fragment μ‚¬μš©

      • λ Œλ”λ§ κ²°κ³Όμ—λŠ” 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμŒ
      return (
        <Fragment>
          <h1>Todo List</h1>
          <div>...</div>
        </Fragment>
      );
    • Fragment의 μ•½μ–΄ μ‚¬μš©

      return (
        <>
          <h1>Todo List</h1>
          <div>...</div>
        </>
      );

    2 λͺ¨λ“  νƒœκ·ΈλŠ” λ‹«λŠ”λ‹€.

    • HTMLμ—μ„œλŠ” λ‹«λŠ” νƒœκ·Έλ₯Ό μƒλž΅ ν•  수 μžˆμ§€λ§Œ JSXλŠ” XMLκ³Ό μœ μ‚¬ν•œ λ¬Έλ²•μ΄λ―€λ‘œ λ‹«λŠ” νƒœκ·Έλ₯Ό 항상 μž‘μ„±ν•΄μ•Ό 함
      • HTML μ˜ˆμ‹œ

        <img src="./logo.png">
        <br>
        <ul>
          <li>두뢀
          <li>κ³„λž€
          <li>라면
        </ul>
      • JSX μ˜ˆμ‹œ

        <img src="./logo.png" />
        <br />
        <ul>
          <li>두뢀</li>
          <li>κ³„λž€</li>
          <li>라면</li>
        </ul>

    3 μš”μ†Œμ˜ 속성λͺ…은 카멜 ν‘œκΈ°λ²•(camel case)을 μ€€μˆ˜ν•΄μ•Ό ν•œλ‹€.

    • 속성λͺ…은 HTML ν‘œμ€€ 속성λͺ…이 μ•„λ‹Œ DOM API μŠ€νŽ™μ— κΈ°λ°˜μ„ λ‘ 

      • stroke-width -> strokeWidth
      • onclick -> onClick
      • onkeyup -> onKeyUp
    • HTMLμ—μ„œ class 속성 μΆ”κ°€

      <div id="todolist" class="todo"></div>
    • μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ class 속성 μΆ”κ°€

      document.querySelector('#todolist').className = 'todo';
      
      
    • JSXμ—μ„œ class 속성 μΆ”κ°€

      <div id="todolist" className="todo"></div>
    • JSXμ—μ„œ class 속성을 λ™μ μœΌλ‘œ μΆ”κ°€

      const todoClass = 'todo';
      <div id="todolist" className={ todoClass }></div>
    • μžλ°”μŠ€ν¬λ¦½νŠΈ μ˜ˆμ•½μ–΄λΌ μΆ©λŒμ„ ν”Όν•˜κΈ° μœ„ν•΄ 속성λͺ… μžμ²΄κ°€ 바뀐 경우

      • class -> className
      • for -> htmlFor

    4 보간법{ }을 μ‚¬μš©ν•  λ•Œμ—λŠ” ν‘œν˜„μ‹μ„ μ‚¬μš©ν•΄μ•Ό 함

    • { } μ•ˆμ—λŠ” λ³€μˆ˜κ°’, λ©”μ„œλ“œ 리턴값 λ“± κ°’λ§Œ μ‚¬μš© κ°€λŠ₯
    • if λ¬Έ, for λ¬Έ 등은 μ‚¬μš©ν•  수 μ—†μŒ
      • if λ¬Έ λŒ€μ‹  μ‚Όν•­ μ—°μ‚°μž μ‚¬μš©

        { item.done ? <s>두뢀</s> : '두뢀' }
      • for λ¬Έ λŒ€μ‹  forEach(), map() λ“± μ‚¬μš©

        {
          for(let i=0; i<itemList.length; i++){
            return item.title;
          }
        }
        { itemList.map(item => item.title) }

    5 λ³΄κ°„λœ HTML λ¬Έμžμ—΄μ€ 인코딩됨

    • { } λ‚΄λΆ€μ˜ 값이 HTML μ½”λ“œκ°€ ν¬ν•¨λœ λ¬Έμžμ—΄μΈ 경우 HTML νƒœκ·Έλ₯Ό μΈμ½”λ”©ν•΄μ„œ μ²˜λ¦¬ν•˜λ―€λ‘œ λΈŒλΌμš°μ €μ—λŠ” νƒœκ·Έκ°€ κ·ΈλŒ€λ‘œ 보여짐

      • XSS (Cross Site Scripting) 같은 곡격에 λŒ€λΉ„ν•˜κΈ° μœ„ν•œ κ·œμΉ™
    • μ˜ˆμ‹œ

      const App(){
        const msg = '<i>World</i>';
        return <span>Hello { msg }</span>
      }
      // λ§Œλ“€μ–΄μ§€λŠ” λ¬Έμžμ—΄: <span>Hello &lt;i&gt;World&lt;/i&gt;</span>
    • μ‹€ν–‰ κ²°κ³Ό

      • Hello World
    • ν•΄κ²° 방법

      1. dangerouslySetInnerHTML 속성을 μ‚¬μš©ν•˜λ©΄ HTML νƒœκ·Έλ₯Ό μΈμ½”λ”©ν•˜μ§€ μ•ŠμŒ
      const App(){
        // { msg }λ₯Ό <span dangerouslySetInnerHTML={{ __html: msg }}></span>둜 λ³€κ²½
        const msg = '<i>World</i>';
        return <span>Hello <span dangerouslySetInnerHTML={{ __html: msg }}></span></span>
      }
      1. JSXλŠ” XSS 곡격에 μ•ˆμ „ν•˜λ―€λ‘œ JSXλ₯Ό μ‚¬μš©
      const App(){
        // const msg = '<i>World</i>';
        const msg = <i>World</i>;
        return <span>Hello { msg }</span>
      }

Props

  • κ°œλ…

    5. 속성 (Props)

    • λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μžμ‹ μ»΄ν¬λ„ŒνŠΈλ‘œ 데이터λ₯Ό 전달할 λ•Œ μ‚¬μš©

      // ch02-start/todo/08.html
      function App(){
        const list = [
          { _id: 1, title: 'React 곡뢀', done: false},
          { _id: 2, title: 'Javascript ν”„λ‘œμ νŠΈ', done: true},
          { _id: 3, title: 'Javascript 곡뢀', done: true},
        ];
      
        return (
          <div id="app">
            <div>
              <Title title="08 Simple Todo List - React Props" />
              <TodoList list={ list } />
            </div>
          </div>
        );
      }
      
      function Title({ title = 'Todo List' }){
        return (
          <div>
            <h1>{ title }</h1>
            <hr />
          </div>
        );
      }
      
      function TodoList({ list }){
        const itemList = list.map(item => {
          return (
            <li key={ item._id }>{ item.title } - { item.done ? 'μ™„λ£Œ' : '진행쀑' }</li>
          );
        });
      
        return (
          <ul className="todolist">
            { itemList }
          </ul>
        )
      }
    • ν•¨μˆ˜μ— 데이터λ₯Ό 전달할 λ•Œ 인수λ₯Ό μ‚¬μš©ν•˜λ“―μ΄ μ»΄ν¬λ„ŒνŠΈμ— 데이터λ₯Ό 전달할 λ•Œ Propsλ₯Ό μ‚¬μš©

      • JSXμ—μ„œ μžμ‹ μ»΄ν¬λ„ŒνŠΈλ₯Ό HTML νƒœκ·Έμ²˜λŸΌ μ‚¬μš©ν•  λ•Œ HTML νƒœκ·Έμ˜ 속성을 μ§€μ •ν•˜λŠ” κ²ƒμ²˜λŸΌ μ‚¬μš©
      <TodoList list={ list } />
    • λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈκ°€ μ „λ‹¬ν•œ μ—¬λŸ¬ 속성이 μžμ‹ μ»΄ν¬λ„ŒνŠΈμ—λŠ” ν•˜λ‚˜μ˜ Props 객체둜 μ „λ‹¬λ˜λ―€λ‘œ 주둜 ꡬ쑰 λΆ„ν•΄ 할당을 μ΄μš©ν•΄μ„œ ν•„μš”ν•œ 속성을 λ°”λ‘œ κΊΌλ‚΄μ„œ μ‚¬μš©

    function TodoList({ list }){
      ....
    }
    • κΈ°λ³Έκ°’ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ Propsκ°€ μ „λ‹¬λ˜μ§€ μ•Šκ±°λ‚˜ undefinedκ°€ λͺ…μ‹œμ μœΌλ‘œ 전달될 λ•Œ 적용됨

      • null, 0 값은 κΈ°λ³Έκ°’μœΌλ‘œ λŒ€μ²΄λ˜μ§€ μ•ŠμŒ
    • μžμ‹ μ΄ 전달받은 Props 전체λ₯Ό μžμ‹ μ»΄ν¬λ„ŒνŠΈμ— μ „λ‹¬ν•˜κ³  싢을 λ•ŒλŠ” μ „κ°œ μ—°μ‚°μžλ₯Ό μ‚¬μš©

      function Profile(props) {
        return (
          <div>
            <Avatar { ...props } />
          </div>
        );
      }
    • Props둜 객체λ₯Ό 전달 받을 λ•Œ μžμ‹ μ»΄ν¬λ„ŒνŠΈκ°€ κ·Έ 값을 직접 λ³€κ²½ν•˜λŠ” 것은 ꢌμž₯ν•˜μ§€ μ•ŠμŒ

      • React의 λ°μ΄ν„°λŠ” λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μžμ‹ μ»΄ν¬λ„ŒνŠΈλ‘œ μ „λ‹¬λ˜λŠ”λ° μžμ‹ μ»΄ν¬λ„ŒνŠΈμ—μ„œ λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈμ˜ 데이터λ₯Ό 직접 μˆ˜μ •ν•˜λ©΄ λ°μ΄ν„°μ˜ 흐름을 μ˜ˆμΈ‘ν•˜κΈ° μ–΄λ €μ›Œμ„œ λ””λ²„κΉ…ν•˜κΈ° μ–΄λ €μš΄ 였λ₯˜λ₯Ό λ§Œλ“€ 수 있음

Props

πŸ“œ 10 Button μ»΄ν¬λ„ŒνŠΈμ— Props 전달

10/
β”œβ”€β”€ node_modules/
β”œβ”€β”€ public/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ Button.tsx
β”‚   β”‚   β”œβ”€β”€ Counter.tsx
β”‚   β”‚   └── Header.tsx
β”‚   β”œβ”€β”€ App.css
β”‚   β”œβ”€β”€ App.tsx
β”‚   β”œβ”€β”€ index.css
β”‚   β”œβ”€β”€ main.tsx
β”‚   └── vite-env.d.ts
β”œβ”€β”€ .gitignore
β”œβ”€β”€ eslint.config.js
β”œβ”€β”€ index.html
β”œβ”€β”€ package.json
β”œβ”€β”€ README.md
β”œβ”€β”€ tsconfig.app.json
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ tsconfig.node.json
└── vite.config.ts
⚠️ **GitHub.com Fallback** ⚠️