1. 클래스형 컴포넌트 (Class Component)
클래스형 컴포넌트는 ES6의 class 문법을 사용하여 정의하는 컴포넌트이다. 리액트의 React.Component를 상속받아 구현하며, 과거 리액트에서 상태 관리와 생명주기(Lifecycle) 기능을 사용하기 위한 표준적인 방법이었다.
특징:
constructor에서this.state를 통해 컴포넌트의 상태(State)를 초기화한다.componentDidMount,componentDidUpdate,componentWillUnmount와 같은 생명주기 메서드를 사용하여 특정 시점에 코드를 실행할 수 있다.render()메서드에서 렌더링할 JSX를 반환한다.- 컴포넌트의 상태와 메서드에 접근할 때
this키워드를 사용해야 한다.
예시 코드:
import React, { Component } from 'react'; class ClassCounter extends Component { constructor(props) { super(props); this.state = { count: 0, }; } handleIncrement = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.handleIncrement}>Increment</button> </div> ); } }
리액트 훅(Hook)이 도입된 이후로는 복잡한
this바인딩과 상대적으로 긴 코드 구조 때문에 특별한 경우가 아니면 함수형 컴포넌트를 사용하는 것이 권장된다.
2. 함수형 컴포넌트 (Functional Component)
함수형 컴포넌트는 자바스크립트 함수를 사용하여 정의하는 컴포넌트이다. 초기에는 상태를 가질 수 없는 단순한 UI 렌더링 용도로 사용되었으나, 리액트 훅(React Hooks)이 도입되면서 상태 관리와 생명주기 기능을 모두 사용할 수 있게 되었다.
특징:
- 코드가 클래스형 컴포넌트에 비해 더 간결하고 직관적이다.
useState,useEffect등의 훅을 통해 상태와 생명주기 관련 로직을 구현한다.this키워드를 사용하지 않아 복잡성이 줄어든다.- 현대 리액트 개발의 표준 방식으로 자리 잡았다.
예시 코드:
import React, { useState } from 'react'; function FunctionalCounter() { const [count, setCount] = useState(0); const handleIncrement = () => { setCount(count + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={handleIncrement}>Increment</button> </div> ); }
3. 변수와 State의 차이
리액트 컴포넌트 내에서 데이터를 다룰 때 일반 변수와 state는 명확한 차이를 가진다.
일반 변수 (Variable):
- 컴포넌트가 다시 렌더링될 때마다 초기화된다. 값이 유지되지 않는다.
- 변수의 값이 변경되더라도 리액트는 이를 감지하지 못하며, 화면을 다시 렌더링하지 않는다(No Re-render). 따라서 UI가 업데이트되지 않는다.
상태 (State):
- 리액트가 직접 관리하는 데이터로, 컴포넌트의 생명주기 동안 값이 유지된다.
setState와 같은 상태 변경 함수를 통해 값이 업데이트되면, 리액트는 이 변화를 감지하고 컴포넌트를 다시 렌더링한다(Trigger Re-render). 이로 인해 변경된state값이 UI에 반영된다.
결론적으로, UI에 동적으로 반영되어야 하는 값은 반드시 state로 관리해야 한다.
4. useState 훅
useState는 함수형 컴포넌트 내에서 상태를 추가하고 관리할 수 있게 해주는 가장 기본적인 훅(Hook)이다.
- 문법:
const [state이름, state변경함수] = useState<타입>(초기값);useState는 배열을 반환하며, 이 배열은 두 개의 요소를 포함한다.state이름: 현재 상태 값.state변경함수: 상태를 업데이트하는 함수. 관례적으로 상태 이름 앞에set을 붙여 작명한다 (예:count->setCount).
5. 상태 변경과 렌더링
함수형 업데이트(prev)를 사용해야 하는 이유
리액트의 상태 업데이트는 비동기적으로 처리될 수 있으며, 성능 최적화를 위해 여러 개의 상태 업데이트를 하나로 묶어 처리하는 배치(Batching) 작업을 수행한다.
문제점:
짧은 시간 안에 여러 번의 상태 업데이트가 발생하는 경우, 이전 상태 값을 기반으로 다음 상태를 계산하면 오래된 상태(Stale State) 값을 참조할 위험이 있다.// 잘못된 예: 1씩 3번 증가시키려 했지만, 실제로는 1만 증가할 수 있다. setCount(count + 1); setCount(count + 1); setCount(count + 1);해결책: 함수형 업데이트
상태 변경 함수에 값을 직접 전달하는 대신, 콜백 함수를 전달할 수 있다. 이 콜백 함수는 이전 상태 값(prev)을 인자로 받아 새로운 상태 값을 반환한다. 리액트는 이 콜백 함수가 실행될 때, 가장 최신의 상태 값을prev인자로 전달하는 것을 보장한다. 따라서 상태가 이전 값에 의존하는 경우, 항상 함수형 업데이트를 사용하는 것이 안전하고 예측 가능하다.// 올바른 예: 이전 상태를 기반으로 안전하게 업데이트한다. setCount(prevCount => prevCount + 1); setCount(prevCount => prevCount + 1); setCount(prevCount => prevCount + 1);
6. 반복문을 위한 map 함수
리액트에서 배열의 각 요소를 UI 컴포넌트로 변환하여 렌더링할 때 map 함수를 사용한다.
el: 배열의 각 요소를 의미한다.index: 배열의 각 요소의 인덱스를 의미한다.key:map을 사용하여 리스트를 렌더링할 때, 각 요소는 고유한keyprop을 가져야 한다.key는 리액트가 어떤 항목이 변경, 추가, 또는 삭제되었는지 식별하는 것을 돕는다.key값으로는 보통 각 요소의 고유 ID를 사용하며, 고유 ID가 없을 경우 최후의 수단으로index를 사용할 수 있지만 권장되지 않는다.
forEach와의 차이점
forEach: 반환 값이 없는(undefined) 메서드이다. 배열의 각 요소를 순회하며 주어진 작업을 수행할 뿐, 새로운 배열을 생성하지 않는다. JSX는undefined를 렌더링하지 않으므로,forEach는 UI 렌더링에 사용할 수 없다.map: 배열의 각 요소에 대해 주어진 함수를 실행한 결과를 모아 새로운 배열을 반환한다. 이 반환된 JSX 요소 배열을 리액트가 렌더링할 수 있다.예시 코드:
function FruitList() { const fruits = [ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }, { id: 3, name: 'Cherry' }, ]; return ( <ul> {/* fruits 배열을 순회하며 각 요소를 <li> 태그로 변환 */} {fruits.map(fruit => ( <li key={fruit.id}>{fruit.name}</li> ))} </ul> ); }
'Programmers' 카테고리의 다른 글
| [47일차]React 상태 관리 및 개발 환경 분석 (0) | 2025.11.17 |
|---|---|
| [46일차]리액트(React)의 Props에 대하여 (0) | 2025.11.14 |
| [44일차]리액트(React) 핵심 개념 시작 정리. (0) | 2025.11.12 |
| [43일차]타입스크립트 2일차: 타입과 객체 지향 프로그래밍의 통합. (0) | 2025.11.11 |
| [42일차]타입스크립트: 언어 개념과 기본 설정. (0) | 2025.11.10 |