λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Lect & Tip/React by GPT

λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈ μž¬μ‚¬μš©μ„±μ„ λ†’μ΄λŠ” μ»΄ν¬μ§€μ…˜ νŒ¨ν„΄

by st곡간 2025. 5. 27.
λ°˜μ‘ν˜•

λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈ μž¬μ‚¬μš©μ„±μ„ λ†’μ΄λŠ” μ»΄ν¬μ§€μ…˜ νŒ¨ν„΄

λ¦¬μ•‘νŠΈλŠ” μ»΄ν¬λ„ŒνŠΈ 기반의 UI κ°œλ°œμ„ 톡해 μ½”λ“œμ˜ λͺ¨λ“ˆν™”와 μž¬μ‚¬μš©μ„±μ„ κ·ΉλŒ€ν™”ν•  수 μžˆλŠ” κ°•λ ₯ν•œ λ„κ΅¬μž…λ‹ˆλ‹€. λŒ€κ·œλͺ¨ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œν•˜λ©΄μ„œ μœ μ§€λ³΄μˆ˜μ„±κ³Ό ν™•μž₯성을 높이기 μœ„ν•΄μ„œλŠ”, λ‹¨μˆœνžˆ μ»΄ν¬λ„ŒνŠΈλ₯Ό λΆ„λ¦¬ν•˜λŠ” 것을 λ„˜μ–΄μ„œ μž¬μ‚¬μš© κ°€λŠ₯ν•œ νŒ¨ν„΄μ„ λ„μž…ν•˜λŠ” 것이 ν•„μˆ˜μ μž…λ‹ˆλ‹€.

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” μ»΄ν¬λ„ŒνŠΈ μ»΄ν¬μ§€μ…˜, κ³ μ°¨ μ»΄ν¬λ„ŒνŠΈ(HOC), λ Œλ” ν”„λ‘œν”„(Render Prop) λ“± λ‹€μ–‘ν•œ νŒ¨ν„΄μ„ ν™œμš©ν•˜μ—¬ λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈμ˜ μž¬μ‚¬μš©μ„±κ³Ό μœ μ§€λ³΄μˆ˜μ„±μ„ ν–₯μƒμ‹œν‚€λŠ” 방법에 λŒ€ν•΄ 심도 있게 λ…Όμ˜ν•˜κ³ μž ν•©λ‹ˆλ‹€.

μ»΄ν¬λ„ŒνŠΈ μ»΄ν¬μ§€μ…˜μ˜ κ°œλ…κ³Ό μž₯점

μ»΄ν¬λ„ŒνŠΈ μ»΄ν¬μ§€μ…˜μ€ λ¦¬μ•‘νŠΈμ˜ κ°€μž₯ 기본적인 섀계 μ² ν•™ 쀑 ν•˜λ‚˜λ‘œ, μ—¬λŸ¬ 개의 μž‘μ€ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‘°ν•©ν•˜μ—¬ λ³΅μž‘ν•œ UIλ₯Ό κ΅¬μ„±ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. 이 방식은 λ‹€μŒκ³Ό 같은 이점을 μ œκ³΅ν•©λ‹ˆλ‹€.

  • λͺ¨λ“ˆν™”: κΈ°λŠ₯ λ‹¨μœ„λ‘œ μ»΄ν¬λ„ŒνŠΈλ₯Ό λΆ„λ¦¬ν•˜μ—¬, 각각의 μ»΄ν¬λ„ŒνŠΈκ°€ 단일 μ±…μž„ 원칙(Single Responsibility Principle)을 λ”°λ₯΄κ²Œ λ©λ‹ˆλ‹€. μ΄λ ‡κ²Œ λΆ„λ¦¬λœ μ»΄ν¬λ„ŒνŠΈλŠ” 각각 λ…λ¦½μ μœΌλ‘œ 개발, ν…ŒμŠ€νŠΈ, μœ μ§€λ³΄μˆ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μž¬μ‚¬μš©μ„±: λ™μΌν•œ UI μš”μ†Œλ‚˜ 둜직이 λ°˜λ³΅λ˜λŠ” 경우, ν•˜λ‚˜μ˜ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ—¬λŸ¬ κ³³μ—μ„œ ν™œμš©ν•  수 μžˆμ–΄ μ½”λ“œ 쀑볡을 쀄이고 νš¨μœ¨μ„±μ„ λ†’μž…λ‹ˆλ‹€.
  • μœ μ—°μ„±: μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‘°ν•©ν•˜λŠ” 방식은, μƒμœ„ μ»΄ν¬λ„ŒνŠΈκ°€ ν•˜μœ„ μ»΄ν¬λ„ŒνŠΈμ˜ λ‚΄μš©μ„ 자유둭게 μ „λ‹¬ν•˜κ±°λ‚˜ μˆ˜μ •ν•  수 있게 ν•¨μœΌλ‘œμ¨ μ‚¬μš©μž μ •μ˜ UIλ₯Ό μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, λ ˆμ΄μ•„μ›ƒ μ»΄ν¬λ„ŒνŠΈμ™€ μ½˜ν…μΈ  μ»΄ν¬λ„ŒνŠΈλ₯Ό λΆ„λ¦¬ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 방식은, λ ˆμ΄μ•„μ›ƒμ€ κ³΅ν†΅λœ μŠ€νƒ€μΌκ³Ό ꡬ쑰λ₯Ό μœ μ§€ν•˜λ©΄μ„œ μ½˜ν…μΈ λ§Œ κ°œλ³„μ μœΌλ‘œ λ³€κ²½ν•  수 μžˆλŠ” μœ μ—°ν•œ λ””μžμΈμ„ κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.

κ³ μ°¨ μ»΄ν¬λ„ŒνŠΈ(Higher-Order Component, HOC)

κ³ μ°¨ μ»΄ν¬λ„ŒνŠΈ(HOC)λŠ” κΈ°μ‘΄ μ»΄ν¬λ„ŒνŠΈλ₯Ό 인자둜 λ°›μ•„ μƒˆλ‘œμš΄ κΈ°λŠ₯μ΄λ‚˜ 데이터λ₯Ό μΆ”κ°€ν•˜μ—¬ ν™•μž₯된 μ»΄ν¬λ„ŒνŠΈλ₯Ό λ°˜ν™˜ν•˜λŠ” νŒ¨ν„΄μž…λ‹ˆλ‹€. HOCλŠ” 곡톡 λ‘œμ§μ„ μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ— 걸쳐 μž¬μ‚¬μš©ν•  λ•Œ 맀우 μœ μš©ν•©λ‹ˆλ‹€.

HOC의 μ£Όμš” νŠΉμ§•

  • μ½”λ“œ μž¬μ‚¬μš©: 곡톡적인 κΈ°λŠ₯(예: 데이터 패칭, 인증, λ‘œκΉ…)을 HOC 내뢀에 μΊ‘μŠν™”ν•¨μœΌλ‘œμ¨, ν•΄λ‹Ή κΈ°λŠ₯을 μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ—μ„œ 쀑볡 없이 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • κ΄€μ‹¬μ‚¬μ˜ 뢄리: UI와 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ λΆ„λ¦¬ν•˜μ—¬, 각각의 μ»΄ν¬λ„ŒνŠΈκ°€ μžμ‹ μ˜ μ±…μž„μ— 집쀑할 수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.
  • μ»΄ν¬λ„ŒνŠΈ ν™•μž₯: κΈ°μ‘΄ μ»΄ν¬λ„ŒνŠΈμ˜ κΈ°λŠ₯을 μ‰½κ²Œ ν™•μž₯ν•  수 μžˆμ–΄, μœ μ§€λ³΄μˆ˜μ„±κ³Ό ν™•μž₯성이 λ†’μ•„μ§‘λ‹ˆλ‹€.

μ•„λž˜λŠ” κ°„λ‹¨ν•œ HOC μ˜ˆμ œμž…λ‹ˆλ‹€. 이 μ˜ˆμ œλŠ” μ‚¬μš©μžμ˜ 인증 μƒνƒœλ₯Ό ν™•μΈν•˜μ—¬, μΈμ¦λ˜μ§€ μ•Šμ€ 경우 둜그인 νŽ˜μ΄μ§€λ‘œ λ¦¬λ‹€μ΄λ ‰νŠΈν•˜λŠ” κΈ°λŠ₯을 μΆ”κ°€ν•©λ‹ˆλ‹€.

import React from 'react';
import { Redirect } from 'react-router-dom';

const withAuth = (WrappedComponent) => {
  return class extends React.Component {
    render() {
      const { isAuthenticated } = this.props;
      if (!isAuthenticated) {
        return <Redirect to="/login" />;
      }
      return <WrappedComponent {...this.props} />;
    }
  };
};

export default withAuth;

μœ„ μ½”λ“œλŠ” withAuthλΌλŠ” HOCλ₯Ό 톡해, μ „λ‹¬λœ μ»΄ν¬λ„ŒνŠΈκ°€ 인증된 μ‚¬μš©μžμ—κ²Œλ§Œ λ…ΈμΆœλ˜λ„λ‘ μ œμ–΄ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 둜그인 κ΄€λ ¨ λ‘œμ§μ„ μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ— λ°˜λ³΅ν•˜μ§€ μ•Šκ³ λ„ μž¬μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ Œλ” ν”„λ‘œν”„(Render Prop) νŒ¨ν„΄

λ Œλ” ν”„λ‘œν”„ νŒ¨ν„΄μ€ μ»΄ν¬λ„ŒνŠΈκ°€ μžμ‹ μ˜ λ Œλ”λ§ λ‘œμ§μ„ ν•¨μˆ˜λ‘œ 전달받아, κ·Έ ν•¨μˆ˜κ°€ λ°˜ν™˜ν•˜λŠ” JSXλ₯Ό λ Œλ”λ§ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€. 이 νŒ¨ν„΄μ€ μ»΄ν¬λ„ŒνŠΈ 간에 μƒνƒœλ‚˜ λ‘œμ§μ„ κ³΅μœ ν•˜λŠ” 데 νš¨κ³Όμ μž…λ‹ˆλ‹€.

λ Œλ” ν”„λ‘œν”„μ˜ μž₯점

  • μœ μ—°ν•œ 데이터 전달: λ Œλ” ν”„λ‘œν”„λ₯Ό μ‚¬μš©ν•˜λ©΄, λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μžμ‹ μ»΄ν¬λ„ŒνŠΈμ— 데이터λ₯Ό μ „λ‹¬ν•˜λŠ” 방식이 λ‹¨μˆœν•΄μ§€κ³ , λ‹€μ–‘ν•œ 쑰건에 따라 λ Œλ”λ§ λ‘œμ§μ„ μ‰½κ²Œ μ»€μŠ€ν„°λ§ˆμ΄μ§•ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 둜직 μΊ‘μŠν™”: λ³΅μž‘ν•œ μƒνƒœ κ΄€λ¦¬λ‚˜ 이벀트 처리λ₯Ό λ³„λ„μ˜ ν•¨μˆ˜λ‘œ λΆ„λ¦¬ν•˜μ—¬, μž¬μ‚¬μš© κ°€λŠ₯ν•œ 둜직으둜 λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ»΄ν¬λ„ŒνŠΈ 독립성: λ Œλ” ν”„λ‘œν”„λ₯Ό μ‚¬μš©ν•˜λ©΄, λ Œλ”λ§κ³Ό 둜직 처리λ₯Ό 뢄리할 수 μžˆμ–΄ μ»΄ν¬λ„ŒνŠΈμ˜ 독립성이 κ°•ν™”λ˜κ³  ν…ŒμŠ€νŠΈκ°€ μš©μ΄ν•΄μ§‘λ‹ˆλ‹€.

μ•„λž˜ μ˜ˆμ œλŠ” 마우슀 μœ„μΉ˜λ₯Ό μΆ”μ ν•˜λŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό λ Œλ” ν”„λ‘œν”„ λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•œ μ˜ˆμž…λ‹ˆλ‹€.

import React, { Component } from 'react';

class MouseTracker extends Component {
  state = { x: 0, y: 0 };

  handleMouseMove = (event) => {
    this.setState({ x: event.clientX, y: event.clientY });
  };

  render() {
    return (
      <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
        {/* λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈμ—μ„œ render prop을 톡해 마우슀 μ’Œν‘œλ₯Ό μ „λ‹¬λ°›μŠ΅λ‹ˆλ‹€. */}
        {this.props.render(this.state)}
      </div>
    );
  }
}

export default MouseTracker;

이제 이 μ»΄ν¬λ„ŒνŠΈλ₯Ό ν™œμš©ν•˜μ—¬, 화면에 마우슀 μ’Œν‘œλ₯Ό 좜λ ₯ν•˜λŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import React from 'react';
import MouseTracker from './MouseTracker';

const App = () => {
  return (
    <div>
      <h2>λ Œλ” ν”„λ‘œν”„ νŒ¨ν„΄μ„ ν™œμš©ν•œ 마우슀 μœ„μΉ˜ 좔적</h2>
      <MouseTracker render={({ x, y }) => (
        <h3>ν˜„μž¬ μœ„μΉ˜: {x} x {y}</h3>
      )} />
    </div>
  );
};

export default App;

이와 같이 λ Œλ” ν”„λ‘œν”„ νŒ¨ν„΄μ„ μ‚¬μš©ν•˜λ©΄, μƒνƒœ 관리와 λ Œλ”λ§ λ‘œμ§μ„ λΆ„λ¦¬ν•˜κ³  μœ μ—°ν•˜κ²Œ μž¬μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

νŒ¨ν„΄ 선택 μ‹œ 고렀사항

μ»΄ν¬λ„ŒνŠΈ μž¬μ‚¬μš©μ„±μ„ 높이기 μœ„ν•΄ μ—¬λŸ¬ νŒ¨ν„΄μ„ λ„μž…ν•  λ•Œ, λ‹€μŒκ³Ό 같은 사항듀을 κ³ λ €ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

  1. ν”„λ‘œμ νŠΈμ˜ 규λͺ¨μ™€ λ³΅μž‘μ„±: μ†Œκ·œλͺ¨ ν”„λ‘œμ νŠΈμ—μ„œλŠ” κ°„λ‹¨ν•œ μ»΄ν¬λ„ŒνŠΈ μ»΄ν¬μ§€μ…˜λ§ŒμœΌλ‘œλ„ μΆ©λΆ„ν•  수 μžˆμ§€λ§Œ, λŒ€κ·œλͺ¨ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” HOCλ‚˜ λ Œλ” ν”„λ‘œν”„ 같은 νŒ¨ν„΄μ„ 톡해 곡톡 λ‘œμ§μ„ μΊ‘μŠν™”ν•˜λŠ” 것이 νš¨κ³Όμ μž…λ‹ˆλ‹€.
  2. μœ μ§€λ³΄μˆ˜μ™€ ν™•μž₯μ„±: 곡톡 κΈ°λŠ₯을 λͺ¨λ“ˆν™”ν•˜κ³  μž¬μ‚¬μš© κ°€λŠ₯ν•œ ν˜•νƒœλ‘œ μž‘μ„±ν•˜λ©΄, λ‚˜μ€‘μ— κΈ°λŠ₯ ν™•μž₯이 ν•„μš”ν•  λ•Œ μˆ˜μ • λ²”μœ„κ°€ μ΅œμ†Œν™”λ©λ‹ˆλ‹€.
  3. 가독성과 ν…ŒμŠ€νŠΈ μš©μ΄μ„±: νŒ¨ν„΄μ„ 적절히 μ„ νƒν•˜μ—¬ μ»΄ν¬λ„ŒνŠΈμ™€ λ‘œμ§μ„ λΆ„λ¦¬ν•˜λ©΄, μ½”λ“œμ˜ 가독성이 ν–₯μƒλ˜κ³  λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό 톡해 각 κΈ°λŠ₯을 λ…λ¦½μ μœΌλ‘œ 검증할 수 μžˆμŠ΅λ‹ˆλ‹€.
  4. 퍼포먼슀 κ³ λ €: HOCλ‚˜ λ Œλ” ν”„λ‘œν”„λ₯Ό μ‚¬μš©ν•  λ•Œ λΆˆν•„μš”ν•œ λ Œλ”λ§μ΄ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ μ΅œμ ν™”ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, React.memoλ‚˜ useCallback을 적절히 ν™œμš©ν•˜μ—¬ μ„±λŠ₯ μ €ν•˜λ₯Ό λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

κ²°λ‘ 

μ»΄ν¬λ„ŒνŠΈ μ»΄ν¬μ§€μ…˜, κ³ μ°¨ μ»΄ν¬λ„ŒνŠΈ(HOC), λ Œλ” ν”„λ‘œν”„ λ“± λ‹€μ–‘ν•œ νŒ¨ν„΄μ€ λ¦¬μ•‘νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ½”λ“œ μž¬μ‚¬μš©μ„±κ³Ό μœ μ§€λ³΄μˆ˜μ„±μ„ 크게 ν–₯μƒμ‹œν‚€λŠ” 핡심 μ „λž΅μž…λ‹ˆλ‹€. μ»΄ν¬λ„ŒνŠΈ μ»΄ν¬μ§€μ…˜μ€ 기본적인 λͺ¨λ“ˆν™”와 μž¬μ‚¬μš©μ„±μ„ μ œκ³΅ν•˜λ©°, HOCλŠ” 곡톡 λ‘œμ§μ„ μΊ‘μŠν™”ν•˜μ—¬ μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ— μ μš©ν•  수 μžˆλŠ” μœ μ—°ν•œ 방법을 μ œκ³΅ν•©λ‹ˆλ‹€. λ˜ν•œ, λ Œλ” ν”„λ‘œν”„ νŒ¨ν„΄μ€ μƒνƒœμ™€ λ Œλ”λ§ λ‘œμ§μ„ λΆ„λ¦¬ν•˜μ—¬ λ”μš± μœ μ—°ν•œ 데이터 전달 및 UI μ»€μŠ€ν„°λ§ˆμ΄μ§•μ„ κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.

μ΄λŸ¬ν•œ νŒ¨ν„΄λ“€μ„ 적절히 μ‘°ν•©ν•˜κ³  ν™œμš©ν•˜λ©΄, μ½”λ“œ 쀑볡을 쀄이고 μœ μ§€λ³΄μˆ˜λ₯Ό μ‰½κ²Œ ν•˜λ©°, ν™•μž₯성이 λ›°μ–΄λ‚œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν”„λ‘œμ νŠΈμ˜ νŠΉμ„±κ³Ό μš”κ΅¬μ‚¬ν•­μ— 맞좰 μ ν•©ν•œ νŒ¨ν„΄μ„ μ„ νƒν•˜κ³ , ν•„μš”μ— 따라 React.memo, useCallback λ“±μ˜ μ΅œμ ν™” 기법을 λ³‘ν–‰ν•˜λ©΄, 보닀 μ•ˆμ •μ μ΄κ³  효율적인 λ¦¬μ•‘νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ΅¬ν˜„ν•  수 μžˆμ„ κ²ƒμž…λ‹ˆλ‹€.

λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈ μž¬μ‚¬μš©μ„± ν–₯상을 μœ„ν•œ λ‹€μ–‘ν•œ νŒ¨ν„΄μ„ μ΄ν•΄ν•˜κ³  μ μš©ν•˜λŠ” 것은 κ°œλ°œμžλ‘œμ„œμ˜ μ—­λŸ‰μ„ 크게 λ†’μ΄λŠ” μ€‘μš”ν•œ λ‹¨κ³„μž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ ‘κ·Ό 방식을 톡해 ν–₯ν›„ λ³΅μž‘ν•œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλ„ μ§€μ†μ μœΌλ‘œ μœ μ§€λ³΄μˆ˜μ™€ ν™•μž₯이 μš©μ΄ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ‹œκΈΈ λ°”λžλ‹ˆλ‹€.

λ°˜μ‘ν˜•

λŒ“κΈ€