React 기본 개념 이해하기, 컴포넌트의 개념과 구조

리액트(React)는 사용자 인터페이스를 구축하기 위해 설계된 JavaScript 라이브러리입니다. 페이스북이 개발하고 관리하며, 현재는 오픈 소스로 공개되어 있는 리액트는 컴포넌트 기반의 개발 방식을 채택하고 있습니다. 이 글에서는 리액트의 기본 개념, 특히 컴포넌트의 개념과 구조에 대해 자세히 살펴보겠습니다. 리액트를 처음 접하는 개발자부터 이미 사용해본 경험이 있는 개발자들도 도움을 받을 수 있도록 다양한 예제와 설명을 제공하겠습니다.

리액트란 무엇인가?

리액트는 단순한 JavaScript 라이브러리를 넘어, 복잡한 사용자 인터페이스를 효율적으로 구축할 수 있도록 돕는 강력한 도구입니다. 리액트의 주요 특징은 다음과 같습니다:

  • 컴포넌트 기반: 리액트는 UI를 독립적이고 재사용 가능한 컴포넌트로 나누어 개발합니다.
  • 가상 DOM: 리액트는 효율적인 UI 업데이트를 위해 가상 DOM을 사용합니다.
  • 선언적 UI: 상태에 따라 UI를 자동으로 관리하는 접근 방식을 제공합니다.
  • 생태계: 다양한 도구와 라이브러리 및 커뮤니티가 활성화되어 있습니다.

컴포넌트의 개념

컴포넌트는 리액트의 핵심 개념으로, UI의 독립적이고 재사용 가능한 조각입니다. 각 컴포넌트는 고유한 상태와 속성을 가지며, 이를 통해 복잡한 UI를 간결하고 효율적으로 구축할 수 있습니다.

컴포넌트의 구조

리액트 컴포넌트는 크게 두 가지 유형으로 나눌 수 있습니다:

  • 함수형 컴포넌트 (Functional Components): JavaScript 함수로 정의되며, props를 인자로 받아 JSX를 반환합니다. 상태 관리는 Hooks를 사용하여 처리합니다.
  • 클래스형 컴포넌트 (Class Components): ES6 클래스 문법을 사용하여 정의되며, React.Component 클래스를 상속받습니다. 상태 관리 및 생명주기 메서드를 사용할 수 있습니다.

함수형 컴포넌트 예제

import React from 'react';

function Greeting(props) {
  return <h1>안녕하세요, {props.name}!</h1>;
}

export default Greeting;

위의 예제는 ‘Greeting’이라는 함수형 컴포넌트를 정의한 것입니다. 이 컴포넌트는 ‘name’이라는 props를 받아 사용자를 환영합니다.

클래스형 컴포넌트 예제

import React, { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>안녕하세요, {this.props.name}!</h1>;
  }
}

export default Greeting;

클래스형 컴포넌트에서도 동일한 기능을 구현할 수 있습니다. ‘render()’ 메서드 안에 JSX를 반환하여 컴포넌트를 UI에 렌더링합니다.

컴포넌트의 Props

리액트에서 ‘props’는 컴포넌트에 전달되는 데이터로, 부모 컴포넌트에서 자식 컴포넌트로 전달됩니다. ‘props’를 통해 컴포넌트의 데이터를 동적으로 변경할 수 있습니다.

Props 사용 예제

function App() {
  return (
    <div>
      <Greeting name="홍길동" />
      <Greeting name="김철수" />
    </div>
  );
}

위의 예제에서는 ‘App’ 컴포넌트가 두 개의 ‘Greeting’ 컴포넌트를 렌더링하고 있습니다. 각각 다른 이름을 props로 전달하여 환영 메시지를 다르게 표시합니다.

컴포넌트의 State

상태(state)는 컴포넌트에서 관리하는 데이터로, 컴포넌트의 생애 주기 동안 변경될 수 있습니다. 상태가 변경되면 리액트는 자동으로 UI를 업데이트합니다.

상태 관리 예제 – 클래스형 컴포넌트

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>현재 카운트: {this.state.count}</p>
        <button onClick={this.increment}>증가</button>
      </div>
    );
  }
}

export default Counter;

위 예제에서 ‘Counter’ 컴포넌트는 카운트를 관리하는 상태를 갖습니다. ‘increment’ 메서드를 호출하여 상태를 변경하고, 그 결과 UI가 자동으로 업데이트됩니다.

상태 관리 예제 – 함수형 컴포넌트

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>현재 카운트: {count}</p>
      <button onClick={increment}>증가</button>
    </div>
  );
}

export default Counter;

함수형 컴포넌트에서는 React의 ‘useState’ 훅을 사용하여 상태를 관리합니다. 훅을 통해 더 간결하게 상태를 설정하고 업데이트할 수 있습니다.

컴포넌트의 생명주기

클래스형 컴포넌트에서는 생명주기 메서드를 통해 컴포넌트의 생성, 업데이트 및 소멸과 관련된 작업을 수행할 수 있습니다. 주요 생명주기 메서드는 다음과 같습니다:

  • componentDidMount: 컴포넌트가 마운트된 후 호출됩니다.
  • componentDidUpdate: 컴포넌트가 업데이트된 후 호출됩니다.
  • componentWillUnmount: 컴포넌트가 언마운트되기 전에 호출됩니다.

생명주기 메서드 예제

import React, { Component } from 'react';

class Timer extends Component {
  constructor(props) {
    super(props);
    this.state = { seconds: 0 };
  }

  componentDidMount() {
    this.interval = setInterval(() => {
      this.setState({ seconds: this.state.seconds + 1 });
    }, 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return <p>타이머: {this.state.seconds}초</p>;
  }
}

export default Timer;

이 ‘Timer’ 컴포넌트는 1초마다 카운트를 증가시키는 타이머입니다. ‘componentDidMount’에서 타이머를 시작하고, ‘componentWillUnmount’에서 타이머를 정리합니다.

결론

리액트의 기본 개념과 컴포넌트의 구조에 대해 알아보았습니다. 컴포넌트는 리액트의 중심 개념으로, 효율적인 UI 개발을 가능하게 합니다. 함수형 컴포넌트와 클래스형 컴포넌트의 각각의 장단점을 잘 파악하고, 상황에 따라 적절히 활용하는 것이 중요합니다. 상태와 props를 통해 컴포넌트를 동적으로 업데이트하고 관리함으로써, 복잡한 애플리케이션을 효과적으로 구축할 수 있습니다.

다음 블로그 포스트에서는 리액트의 생태계와 더 깊이 있는 주제를 다룰 예정이니, 많은 관심 부탁드립니다!