๐Ÿ“’ Study/๐ŸŒ React

[ React ] ์ปดํฌ๋„ŒํŠธ / React ๊ธฐ์ดˆ ์ •๋ฆฌ ๋…ธํŠธ

EarthSea 2025. 1. 10. 00:26
์•„๋ž˜์˜ ๊ธ€์€ ์ธํ”„๋Ÿฐ "์‹ค๋ฌด์ค‘์‹ฌ! FE ์ž…๋ฌธ์ž๋ฅผ ์œ„ํ•œ React" ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ๋‚œ ํ›„์— ์ •๋ฆฌํ•˜๊ณ  ๊ธฐ๋กํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

 

 

์ปดํฌ๋„ŒํŠธ๋ž€?

  • React๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๋Š” ๋‹จ์œ„๋กœ ํ™”๋ฉด์ด ๊ตฌ์„ฑ
  • ์Šค์Šค๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์บก์Аํ™”๋œ ์ฝ”๋“œ ์กฐ๊ฐ
  • ํ•˜๋‚˜์˜ JSX๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜

 

 

์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

์•„๋ž˜์˜ App ์ปดํฌ๋„ŒํŠธ๋ฅผ Hello ์ปดํฌ๋„ŒํŠธ์™€ World ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•˜๊ธฐ

export default function App() {
  return (
    <div>
      <h1>Hello,</h1>
      <h2>World</h2>
    </div>
  );
}

 

[ App.js ] 

import Hello from "./Hello.js";
import World from "./World.js";

export default function App() {
  return (
    <div>
      <Hello></Hello>
      <World />
    </div>
  );
}

[ Hello.js ]

export default function Hello() {
  return <h1>Hello</h1>;
}

[ World.js ] 

export default function World() {
  return <h2>World</h2>;
}

 

** export default๋Š” ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋‚ด๋ณด๋‚ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
** import ๋Š” ๋ชจ๋“ˆ์„ ๋ณด๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

 

JSX์™€์˜ ์ฐจ์ด

  • ์ปดํฌ๋„ŒํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ์ž์‹ ๋งŒ์˜ ๊ณ ์œ ํ•œ ๋กœ์ง์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.
  • ์Šค์Šค๋กœ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ( ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜๋ฉด ์•Œ์•„์„œ ๋ฐ˜์˜ )

 

์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

  1. ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์€ PascalCase๋กœ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค.
  2. ์ปดํฌ๋„ŒํŠธ๋Š” ์˜๋ฏธ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์„œ ํŒŒ์ผ์„ ๋ถ„๋ฆฌํ•œ๋‹ค.
  3. ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์€ ์ผ๋ฐ˜์ ์œผ๋กœ App์ด๋‹ค.

 

 

Props

  • properties์˜ ์ค„์ž„๋ง
  • ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚ด๋ ค์ฃผ๋Š” ๋ฐ์ดํ„ฐ
fuction App() {
	return (
    	<div>
        	<MyComponent value={'test'}/>
        </div>
    );
}

function MyComponent(props) {
	return <div>{props.value}</div>;
}

App ์ปดํฌ๋„ŒํŠธ์—์„œ MyComponent์—๊ฒŒ 'test'๋ผ๋Š” ๊ฐ’์„ ์ „๋‹ฌํ•˜๊ณ , ์ „๋‹ฌ๋ฐ›์€ ์ปดํฌ๋„ŒํŠธ๋Š” App์—์„œ ํ• ๋‹นํ•œ value๋ผ๋Š” ๋ณ€์ˆ˜๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

 

fuction App() {
	return (
    	<div>
        	<MyComponent>
                <h1>value</h1>
            </MyComponent>
        </div>
    );
}

function MyComponent(props) {
	return <div>{props.children}</div>;
}

ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ํƒœ๊ทธ๋กœ ๊ฐ์‹ผ ๊ฐ’์ด props๋กœ ์ „๋‹ฌ๋  ๋•Œ์—๋Š” children์ด๋ผ๋Š” ๋ณ€์ˆ˜๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

Props ํ™œ์šฉ ํŒ

  • ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น ๊ตฌ๋ฌธ์„ ์ž˜ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • ํŠน์ • Props์— ๊ธฐ๋ณธ ๊ฐ’์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. (defaultProps)
  • Props๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด๋‹ค.

 

 

์˜ˆ์ œ) ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‹ค๋ฅธ ๊ฐ’ ์ถœ๋ ฅํ•ด๋ณด๊ธฐ

[ components/Heading.js ]

export default function Heading(props) {
  if (props.type === "h2") {
    return <h2>{props.children}</h2>;
  }
  return <h1>{props.children}</h1>;
}

[ App.js ]

// import Hello from "./components/Hello";
// import World from "./components/World";
import Heading from "./components/Heading";

// Heading ์ด๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  Hello, World ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ฉํ•˜๊ธฐ
export default function App() {
  return (
    <div>
      <Heading type="h1">Hello</Heading>
      <Heading type="h2">World</Heading>
    </div>
  );
}

 

 

 

State

  • ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ผ์ข…์˜ ๋ณ€์ˆ˜
  • ์ปดํฌ๋„ŒํŠธ ์Šค์Šค๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์กด์žฌ
fuction App() {
    const [value, setValue] = useState(0);

    return {
        <div>{value}</div>
    };
}

useState()๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๊ทธ์— ๋Œ€ํ•œ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ํ•˜๋‚˜์˜ State์™€ setterํ•จ์ˆ˜๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

์˜ˆ์ œ) ๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๋Š” ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ

// - value๋ฅผ state๋กœ ๋งŒ๋“ค๊ธฐ
// - Increase ๋ฒ„ํŠผ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ (+ํ•จ์ˆ˜ํ˜• ์ธ์ž๋กœ)
// - Reset ๋ฒ„ํŠผ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ

export default function App() {
  let value = 0;

  return (
    <div>
      <h1>value: {value}</h1>
      <button
        onClick={() => {
          value = value + 1;
        }}
      >
        Increase value
      </button>
      <button>Reset value</button>
    </div>
  );
}

๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด value๊ฐ’์€ ์ฆ๊ฐ€ํ•˜์ง€๋งŒ, ํ™”๋ฉด์—์„œ๋Š” ๊ฐ’์ด ๋ Œ๋”๋ง๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

์ง€๊ธˆ ํ™”๋ฉด์€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋œ ํ™”๋ฉด ์ƒํƒœ๋กœ ์žฌ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์—ฌ๊ธฐ์„œ State ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด๋ณด์ž.

 

// - value๋ฅผ state๋กœ ๋งŒ๋“ค๊ธฐ
// - Increase ๋ฒ„ํŠผ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ (+ํ•จ์ˆ˜ํ˜• ์ธ์ž๋กœ)
// - Reset ๋ฒ„ํŠผ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ
import { useState } from "react";

export default function App() {
  const [value, setValue] = useState(0);

  return (
    <div>
      <h1>value: {value}</h1>
      <button
        onClick={() => {
          console.log("Increase value1", value);
          setValue(value + 1);
          console.log("Increase value2", value);
        }}
      >
        Increase value
      </button>
      <button
        onClick={() => {
          setValue(0);
        }}
      >
        Reset value
      </button>
    </div>
  );
}

์—ฌ๊ธฐ์„œ useState(0)๋ผ๋Š” ํ•จ์ˆ˜๋Š” ๊ธฐ๋ณธ๊ฐ’์ธ 0์ด ์ €์žฅ๋œ value๋ผ๋Š” ๋ณ€์ˆ˜์™€ setValue๋ผ๋Š” setter ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋•Œ, setValue ํ•จ์ˆ˜๋Š” value์˜ ๊ฐ’์„ ๋ณ€ํ™˜์‹œํ‚ค๊ณ , App์ด๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

 

์—ฌ๊ธฐ์„œ console์„ ํ™•์ธํ•˜๋ฉด

setValue() ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋จ๊ณผ ๋™์‹œ์— value๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Š” Stateํ•จ์ˆ˜๋Š” ๋ชจ๋“  ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰์ด ๋œ ํ›„ ํ•œ๊บผ๋ฒˆ์— ๋ Œ๋”๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

 

ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ vs ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ

ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ
ํด๋ž˜์‹ ๋ฌธ๋ฒ•์œผ๋กœ ์•„์ง๋„ ์‚ฌ์šฉ๋˜๊ณ  ๊ตฌํ˜„ํ•œ ์˜›๋‚  ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๊ฐ€ ํด๋ž˜์Šค๋ณด๋‹ค ๋‹จ์ˆœํ•œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•˜๋ฉฐ ๋Œ€์„ธ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ค‘
์•„์ง๋„ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์„œ๋น„์Šค์—์„œ ํ™œ์šฉ๋˜๊ณ  ์žˆ๊ธฐ์— ํ•™์Šต ์ฝ”๋“œ ์žฌํ™œ์šฉ์„ฑ์— ์œ ๋ฆฌํ•œ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ ์ œ์ž‘ ๋ฐฉ์‹

 

ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ

ํด๋ž˜์Šค ๋ฌธ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•œ ์ปดํฌ๋„ŒํŠธ

 

์˜ˆ์ œ) ์•ž์„œ ๊ตฌํ˜„ํ•œ ๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๋Š” ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ๋ฅผ ํด๋ž˜์Šคํ˜•์œผ๋กœ ๊ตฌํ˜„

import React, { Component } from 'react';

export default class App extends Component {
  state = {
    value: 0
  };

  constructor(props) {
    super(props);
    this.state = {
      value: 1
    };
  }

  resetValue() {
    this.setState({ value: 0 });
  }

  render() {
    return (
      <div>
        <h1>value: {this.state.value}</h1>
        <button
          onClick={() => {
            this.setState((state) => ({
              value: state.value + 1
            }));
          }}
        >
          Increase value
        </button>
        <button
          onClick={this.resetValue.bind(this)}
        >
          Reset value
        </button>
      </div>
    );
  }
}

 

 

ํด๋ž˜์Šค๊ฐ€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋˜๊ธฐ ์œ„ํ•ด์„œ react์— ์žˆ๋Š” Component๋ฅผ ์ƒ์†๋ฐ›์•„์•ผ ํ•œ๋‹ค.

 

 

[ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ ]

[ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ]

state ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๋Š” ๋ฐ ์žˆ์–ด์„œ ์ฐจ์ด๊ฐ€ ๋‚œ๋‹ค.

 

 

this.resetValue์—์„œ์˜ this๋Š” App ํ•จ์ˆ˜ ์ „์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹Œ onClick์ด๋ผ๋Š” ์š”์†Œ๊ฐ€ ์‹คํ–‰๋œ button์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋œ๋‹ค. ํ•˜์ง€๋งŒ, button์€ setState๋ฅผ ๊ฐ€์ง€๊ธฐ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ˜„์žฌ App์„ ๊ฐ€๋ฆฌํ‚ค๋Š” this๋ฅผ bind๋ฅผ ํ•ด์ค˜์•ผ๋งŒ ํ•œ๋‹ค.

 

 

Hooks์˜ ๋“ฑ์žฅ ์ด์œ 

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

 

 

 

์‹ค์Šต) ์Šคํ„ฐ๋””ํŒŒ์ด ๊ฐ•์˜ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

 

[ App.js ]

import CourseCard from './components/CourseCard';

function App() {
  return (
    <div style={{ padding: 30 }}>
      <CourseCard
        img="https://dst6jalxvbuf5.cloudfront.net/media/images/Course/cover_image/210909_191531/23.png"
        tags={['๋ฐœํ‘œ', 'ํŒจํ‚ค์ง€', '์ตœ๋Œ€ํ• ์ธ']}
        title="๋น„์ฆˆ๋‹ˆ์Šค ์˜ฌ์ธ์›, ๋ฐฉ๊ตฌ์„ ์–ดํ•™์—ฐ์ˆ˜ ํŒจํ‚ค์ง€"
        startPrice={349000}
        types={['๋™์˜์ƒ ๊ฐ•์˜']}
      />
    </div>
  );
}

export default App;
 

[ CourseCard.js ]

import "./CourseCard.css";

function CourseCard({ img, tags, title, startPrice, types }) {
  return (
    <div className="CourseCard">
      <div className="cover">
        <img src={img} alt="" />
      </div>
      <div>
        <ul className="tags">
          {tags.map((item, idx) => (
            <li key={idx} className="tag">
              {item}
            </li>
          ))}
        </ul>
      </div>
      <div className="name">{title}</div>
      <div className="price">{startPrice.toLocaleString()}์›๋ถ€ํ„ฐ</div>
      <div>
        <ul className="types">
          {types.map((item, idx) => (
            <li key={idx} className="type">
              {item}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

export default CourseCard;