클래스형 컴포넌트와 함수형 컴포넌트

wltjd1688·2025년 4월 8일

풀사이클

목록 보기
49/74

클래스형 컴포넌트

초기에 사용하던 컴포넌트 형태로 Component 클래스를 상속하여 컴포넌트를 작성한다.

import {Component} from "react";

// 컴포넌트를 상속해서 만들어야 한다.
class ClassCom extends Component {
  	// 랜더를 통해서 기능을 보여준다는 걸 표현해줘야 한다.
    render(){
        return (
            <div>
                클래스형 컴포넌트
            </div>
        )
    }
}

// export를 통해 ClassCom형태의 클래서형 컴포넌트를 내보내야 사용할 수 있다.
export default ClassCom;

이 방식은 상태 및 라이프사이클 관리가 내장되어 있으며, 컴포넌트 내부의 메서드를 통해 기능을 구현한다. 단점으로는 코드가 장황해지고 재사용성이 떨어진다.

함수형 컴포넌트

리액트가 16버전 이후로 권장하는 컴포넌트 형태
장점으로는 간결한 구조와 가독성가 있다.

원래는 스테이트와 라이프사이클의 api사용이 불가능 했는데 리액트 16.8버전 이후로 훅을 도입하여 해결하면서 리액트에서는 함수형 컴포넌트 사용을 권장하고있다.

함수형 예시이다.

import React from "react";

function FuncCom(){
    return (
        <div>
            함수형 컴포넌트
        </div>
    )
}

export default FuncCom;

화살표 함수로도 만들 수 있다고 한다.

import React from "react";

const FuncCom = () => {
    return (
        <div>
            함수형 컴포넌트
        </div>
    )
}

export default FuncCom;

구조 분해 할당 이해

React에서는 컴포넌트의 상태를 관리할 때 클래스형 컴포넌트의 경우 this.state와 this.setState를 사용하였으나, 함수형 컴포넌트에서는 useState 훅을 사용한다.

const [todos, setTodos] = useState<string[]>(['공부하기','잠자기','미팅하기']);

이러한 형태를 구조 분해 할당이라고 한다.


구조분해할당은 다음과 같이 확인할 수 있다.
이렇게 구조 분해 할당을 사용하여 상태와 상태를 갱신하는 함수를 분리하면, 데이터를 외부에서 임의로 수정하지 않고 캡슐화된 방식으로 관리할 수 있다. 이 방식은 데이터의 무결성을 유지하는 데 도움을 준다.

데이터 반복 처리하기(map함수 활용하기)

리액트에서는 배열 데이터를 화면에 반복 처리할 때 map 함수를 사용한다. 아래 코드는 과일 목록을 리스트로 만들어 화면에 출력하는 예시이다.

import React, { useState } from "react";

const MapTest = () =>{
    const fruits = ['apple','banana','orange'];

    return(
        <div>
            <h2>과일</h2>
            <ul>{
                    fruits.map((firut, idx)=>{
                        return (<li key={idx}>{firut}</li>)
                    })
                }
            </ul>
        </div>
    )
}

export default MapTest

각 요소를 렌더링할 때 key 속성을 부여하여 리스트 내 요소들의 변경 사항을 인식하는 데 도움을 준다.

체크박스 기능 추가

체크박스를 이용하여 할 일의 완료 여부를 표시한다. 체크박스의 변경 이벤트(onChange)를 통해 특정 아이템의 상태를 갱신하는데, 불변성(immutability)을 유지하기 위해 스프레드 연산자를 사용하여 기존 객체를 복사한 후 변경된 값을 반환한다.

const handleCheckedChange = (itemId: number) => {
    setTodos((prevItems) =>
        prevItems.map((item) =>
            item.id === itemId ? { ...item, isChecked: !item.isChecked } : item
        )
    );
}

여기서 주의할 점은, 기존의 객체를 그대로 변경하지 않고 새로운 객체를 생성하는 '얕은 복사' 방식을 사용한다는 것이다. 이는 리액트 상태 관리에서 불변성을 유지하는 핵심 기법이다.

**깊은 복사와 얉은 복사
React에서 상태를 직접 변경하지 않고 새로운 객체나 배열을 만들어 업데이트하는 이유는 불변성을 유지하기 위함이다.
스프레드 연산자(...)를 사용하면 얕은 복사(shallow copy)가 이루어진다. 이 경우 객체 내부의 중첩된 객체까지 복사하고자 하면 깊은 복사(deep copy)를 고려해야 한다.
위 예제에서는 주로 단순한 객체 구조를 사용하기 때문에 얕은 복사 방식으로 충분히 상태를 보호하며 사용한다.

새로운 게시물 추가하기

사용자의 입력을 받아 새로운 할 일을 추가하는 방법을 알아본다. 입력 필드의 값은 별도의 상태(newTodo)로 관리하며, 입력 값이 공백이 아닌 경우에만 새로운 할 일을 추가한다.

const addTodo = () => {
    if(newTodo.trim() !== ''){
        setTodos([...todos, { id: Date.now(), text: newTodo, isChecked: false }]);
        setNewTodo('');
    }
}

여기서 스프레드 연산자를 활용하여 기존 todos 배열을 복사한 후, 새로운 아이템을 추가한다. 이 방식은 배열의 불변성을 유지하면서 새로운 값을 할당하는 방법으로, React의 상태 관리 원칙을 따른다.

또한, 버튼 클릭 시 addTodo 함수가 호출되어 새로운 항목이 리스트에 추가된다.

시계 추가하기

실시간으로 현재 시간을 표시하는 시계를 만들었다.
useState로 날짜 객체를 관리하고, setInterval을 사용하여 1초마다 현재 시간을 갱신한다.

import React, {useState} from "react";

// const Timer: React.FC = () =>{
//     const [seconds, setSeconds] = useState<number>(0);

//     return(
//         <div>
//             <h2>타이머: {seconds}초</h2>
//             <button onClick={
//                 function(){
//                     setInterval(()=>{
//                         setSeconds((prev)=>prev + 1)
//                     }, 1000)
//                 }
//             }>시작</button>
//         </div>
//     )
//}

const Clock: React.FC = () =>{
    const [time, setTime] = useState<Date>(new Date());

    setInterval(()=>{
        setTime(new Date());
    }, 1000);

    return(
        <div>
            현재 시간 : {time.toLocaleTimeString()}
        </div>
    )
}


export default Clock;

게시물 삭제하기

리스트에서 특정 할 일을 삭제하는 기능을 구현한다. 삭제 버튼 클릭 시 해당 아이템을 제외한 새로운 배열을 setTodos를 통해 갱신한다.

const removeTodo = (id: number) => {
    setTodos(todos.filter((todo) => todo.id !== id));
}

props의 사용

컴포넌트끼리 정보를 공유할때 넘겨줄 때 사용하는 기능이다.

import React, { Component } from "react";

interface MyProps{
    waether: string;
    children: React.ReactNode;
}

// const MyWeather : React.FC<MyProps> = ({children, waether}) =>{
//     // const {children, waether} = props;

//     return(
//         <div>
//             {children}<p></p>
//             오늘의 날씨는 {waether} 입니다.
//         </div>
//     )
// }

class MyWeather extends Component<MyProps>{
    render(){
    const {children, waether} = this.props;
    return (
            <div>
                {children}<p></p>
                오늘의 날씨는 {waether} 입니다.
            </div>
        )
    }
}

export default MyWeather

모달 대화상자를 이용한 상세정보 구현하기

import React from "react";
import { Modal, ModalBody } from "react-bootstrap";

type Todo = {
    id : number;
    text: string;
    isChecked: boolean;
}

type TodoModalProps = {
    show: boolean;
    todo: Todo | null;
    handleClose: () => void;
}

const TodoModal : React.FC<TodoModalProps> = ({show, todo, handleClose}) => {
    return (
        <div>
            <Modal show={show} onHide={handleClose} centered>
                <Modal.Header closeButton>
                    <Modal.Title>Todo 상세 정보</Modal.Title>
                </Modal.Header>
                <Modal.Body>{todo?.text}</Modal.Body>
            </Modal>
        </div>
    )
}

export default TodoModal;
profile
일단 해!!!!

0개의 댓글