Front-end/React

React์˜ Composition vs Inheritance ๐ŸŒŸ

xeunnie 2025. 2. 22. 01:00
728x90
๋ฐ˜์‘ํ˜•

React์˜ Composition vs Inheritance ๐ŸŒŸ

 

React ๊ฐœ๋ฐœ์ž ๋ฌธ์„œ์˜ Composition vs Inheritance ์„น์…˜์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ํ™•์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” **์ปดํฌ์ง€์…˜(Composition)**์ด **์ƒ์†(Inheritance)**๋ณด๋‹ค React์˜ ์ฒ ํ•™์— ๋” ์ ํ•ฉํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๋Š” ์ ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” React ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋ฉด์„œ ๋” ํ’๋ถ€ํ•œ ์‚ฌ๋ก€์™€ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜Š

 

1๏ธโƒฃ ์ปดํฌ์ง€์…˜(Composition)์ด๋ž€?

 

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

 

๐Ÿ› ๏ธ ์ปดํฌ์ง€์…˜์˜ ํ•ต์‹ฌ ๋ฐฉ์‹

 

React์—์„œ ์ปดํฌ์ง€์…˜์€ ๋ณดํ†ต props.children๊ณผ ๊ฐ™์€ ํŠน์ˆ˜ prop ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค.

 

์˜ˆ์ œ 1: props.children ํ™œ์šฉ

 

function Card({ children }) {

  return <div className="card">{children}</div>;

}

 

function App() {

  return (

    <Card>

      <h1>React Composition</h1>

      <p>์ปดํฌ์ง€์…˜์€ ์ƒ์†๋ณด๋‹ค ๋” ์œ ์—ฐํ•ด์š”!</p>

    </Card>

  );

}

 

์˜ˆ์ œ 2: ํŠน์ • ์˜์—ญ์— ์‚ฝ์ž…ํ•˜๊ธฐ

 

function SplitPane({ left, right }) {

  return (

    <div className="split-pane">

      <div className="left-pane">{left}</div>

      <div className="right-pane">{right}</div>

    </div>

  );

}

 

function App() {

  return (

    <SplitPane

      left={<p>์™ผ์ชฝ ์ฝ˜ํ…์ธ </p>}

      right={<p>์˜ค๋ฅธ์ชฝ ์ฝ˜ํ…์ธ </p>}

    />

  );

}

 

๐ŸŒŸ ์žฅ์ 

1. ์œ ์—ฐ์„ฑ: ๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์‹ ์˜ ์—ญํ• ๋งŒ ๋‹ด๋‹นํ•˜๋ฉฐ, ์™ธ๋ถ€์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ์กฐ๋ฆฝ๋ฉ๋‹ˆ๋‹ค.

2. ์žฌ์‚ฌ์šฉ์„ฑ: ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. React์˜ ์ฒ ํ•™์— ๋ถ€ํ•ฉ: React๋Š” UI๋ฅผ ์กฐํ•ฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค.

 

2๏ธโƒฃ ์ƒ์†(Inheritance)์ด๋ž€?

 

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

 

๐Ÿ› ๏ธ React์—์„œ ์ƒ์† ์‚ฌ์šฉ ์˜ˆ์ œ

 

class Button extends React.Component {

  render() {

    return <button>{this.props.label}</button>;

  }

}

 

class SubmitButton extends Button {

  render() {

    return <button>{this.props.label || "Submit"}</button>;

  }

}

 

๐Ÿšซ React์—์„œ ์ƒ์†์„ ์ง€์–‘ํ•˜๋Š” ์ด์œ 

1. ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•ด์ง: ์ƒ์† ๊ณ„์ธต์ด ๊นŠ์–ด์ง€๋ฉด ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.

2. ์œ ์—ฐ์„ฑ ๋ถ€์กฑ: ์ƒ์†์€ ์ปดํฌ๋„ŒํŠธ์˜ ์—ญํ• ์„ ๊ณ ์ •์‹œํ‚ค๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์–ด ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋–จ์–ด๋œจ๋ฆฝ๋‹ˆ๋‹ค.

3. React์˜ ์ฒ ํ•™๊ณผ ์–ด๊ธ‹๋‚จ: React๋Š” โ€œํ•ฉ์„ฑโ€์„ ํ†ตํ•œ ์กฐ๋ฆฝํ˜• ์„ค๊ณ„๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

 

3๏ธโƒฃ React์—์„œ ์ƒ์†๋ณด๋‹ค ์ปดํฌ์ง€์…˜์„ ์„ ํ˜ธํ•˜๋Š” ์ด์œ 

 

React๋Š” UI๋ฅผ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆ„๋Š” ๋ฐ ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค. ์ƒ์†๋ณด๋‹ค ์ปดํฌ์ง€์…˜์„ ์„ ํ˜ธํ•˜๋Š” ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

 

โœ… ์ปดํฌ์ง€์…˜์˜ ์žฅ์ 

โ€ข ๊ตฌ์„ฑ ๊ฐ€๋Šฅ์„ฑ: ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•ด ๋ณต์žกํ•œ UI๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ€ข ๋ถ„๋ฆฌ๋œ ์ฑ…์ž„: ๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ ์ž์‹ ์˜ ์—ญํ• ๋งŒ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

โ€ข ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋Š” ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

โ€ข ์ฝ”๋“œ ๊ฐ„์†Œํ™”: ์ƒ์† ๊ณ„์ธต์„ ํ”ผํ•˜๋ฉด์„œ ๋‹จ์ˆœํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

4๏ธโƒฃ ์‹ค์ „ ํ™œ์šฉ: ์ปดํฌ์ง€์…˜์„ ํ™œ์šฉํ•œ ๋‹ค์–‘ํ•œ ์‚ฌ๋ก€

 

๐ŸŒŸ ์ปจํŠธ๋กค๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์™€ ์Šฌ๋กฏ ํŒจํ„ด

 

์ปดํฌ์ง€์…˜์€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ปจํŠธ๋กค๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋‚˜ ์Šฌ๋กฏ ํŒจํ„ด์—์„œ๋„ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

์ปจํŠธ๋กค๋˜๋Š” ์ปดํฌ๋„ŒํŠธ

 

function Input({ label, value, onChange }) {

  return (

    <label>

      {label}

      <input value={value} onChange={onChange} />

    </label>

  );

}

 

function App() {

  const [name, setName] = React.useState("");

 

  return (

    <Input

      label="Name:"

      value={name}

      onChange={(e) => setName(e.target.value)}

    />

  );

}

 

์Šฌ๋กฏ ํŒจํ„ด

 

function Modal({ header, footer, children }) {

  return (

    <div className="modal">

      <div className="header">{header}</div>

      <div className="content">{children}</div>

      <div className="footer">{footer}</div>

    </div>

  );

}

 

function App() {

  return (

    <Modal

      header={<h2>๋ชจ๋‹ฌ ์ œ๋ชฉ</h2>}

      footer={<button>๋‹ซ๊ธฐ</button>}

    >

      <p>์—ฌ๊ธฐ์— ๋ชจ๋‹ฌ ๋‚ด์šฉ์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค!</p>

    </Modal>

  );

}

 

5๏ธโƒฃ ์ปดํฌ์ง€์…˜๊ณผ ์ƒ์†์˜ ํ˜ผ์šฉ์€ ๊ฐ€๋Šฅํ• ๊นŒ?

 

React์—์„œ๋Š” ์ƒ์†์„ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ, ํŠน์ • ์ƒํ™ฉ์—์„œ๋Š” ์ œํ•œ์ ์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ณตํ†ต์ ์ธ ๋ฉ”์„œ๋“œ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์ƒ์†์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ HOC(Higher-Order Component) ๋˜๋Š” Hook์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

6๏ธโƒฃ ์ปดํฌ์ง€์…˜ vs ์ƒ์†: ์–ธ์ œ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?

โ€ข ์ปดํฌ์ง€์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:

โ€ข ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ๊ด€๊ณ„๊ฐ€ ๋А์Šจํ•˜๊ณ , ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•  ๋•Œ.

โ€ข ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ.

โ€ข ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:

โ€ข ์•„์ฃผ ๋“œ๋ฌผ๊ฒŒ, ๊ณตํ†ต์ ์ธ ๋กœ์ง์ด ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋งŒ ์‚ฌ์šฉ.

 

๊ฒฐ๋ก : React ๊ฐœ๋ฐœ์ž์˜ ์„ ํƒ์€?

 

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

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น!๐ŸŒท

728x90
๋ฐ˜์‘ํ˜•