JSX와 React 요소, 리스트와 키를 사용한 반복 렌더링

React는 현대 웹 개발에서 매우 인기 있는 라이브러리 중 하나입니다. 다양한 UI 컴포넌트를 만들고 관리할 수 있는 힘을 제공하고, 그 중에서도 JSX는 핵심적인 역할을 합니다. 이 글에서는 JSX의 정의와 특징, React 요소, 그리고 리스트와 키를 사용한 반복 렌더링에 대해 자세히 살펴보겠습니다.

JSX란?

JSX는 JavaScript XML의 약자로, React에서 사용되는 문법입니다. JSX는 JavaScript 코드와 HTML을 혼합하여 사용할 수 있게 해주며, 이를 통해 직관적이고 가독성이 높은 UI를 작성할 수 있습니다. JSX를 사용하면, 복잡한 구조의 UI 컴포넌트를 만들 때 더 간결하고 이해하기 쉽게 코드를 작성할 수 있습니다.

JSX의 주요 특징

  • HTML과 유사한 문법: JSX는 HTML처럼 생겼지만, 실제로는 JavaScript 객체로 변환됩니다.
  • 표현력: JSX에서는 JavaScript 표현식을 중괄호 {} 안에 써서 변수나 함수의 값을 사용할 수 있습니다.
  • 자동으로 자식 요소 맵핑: JSX에서는 컴포넌트를 호출할 때 태그 이름으로 자식 요소를 자동으로 맵핑하는 기능이 있습니다.

JSX 코드 예제

            
{`const element = 

Hello, world!

;`}

위의 코드에서, element는 JSX로 작성된 React 엘리먼트를 나타냅니다. JSX는 컴포넌트를 정의하는 데 사용됩니다.

React 요소

React 요소는 React의 기본 빌딩 블록입니다. React 요소는 컴포넌트와 유사하지만, React 컴포넌트를 인스턴스화하는 것이 아닙니다. 요소는 React의 가상 DOM을 업데이트하는데 중요한 역할을 하며, 이러한 요소는 불변성이 특징입니다. 즉, 요소 자체는 생성된 후 절대 변경되지 않습니다.

React 요소 생성하기

            
{`const element = React.createElement('h1', null, 'Hello, world!');`}
            
        

위의 코드에서, React.createElement 메소드를 사용하여 React 요소를 생성했습니다. 이 방법은 JSX가 내부적으로 사용하는 방법입니다. JSX를 사용하면 더 간결하게 작성할 수 있습니다.

리스트와 키를 사용하는 반복 렌더링

React에서는 리스트를 쉽게 렌더링할 수 있습니다. 이를 통해 유동적인 데이터 표현이 가능합니다. 리스트를 렌더링할 때는 각 요소에 고유한 키를 부여해야 합니다. 이 키는 React가 어떤 항목이 변경, 추가 또는 삭제되었는지를 식별하는 데 도움을 줍니다.

리스트 렌더링 예제

다음은 간단한 리스트를 렌더링하는 예시입니다. 이 예제에서는 동적 데이터로 쉽게 변경할 수 있는 유용한 방법을 보여줍니다.

            
{`const fruits = ['사과', '바나나', '체리'];

function FruitList() {
    return (
        
    {fruits.map((fruit, index) => (
  • {fruit}
  • ))}
); }`}

위의 FruitList 컴포넌트는 fruits 배열을 맵핑하여 각 과일을 리스트 항목으로 표시합니다. 여기서 각 li 태그에는 고유한 key 속성을 부여해야 합니다. 이 예제에서는 인덱스를 키로 사용했지만, 실무에서는 더 고유한 키를 사용하는 것이 좋습니다.

키의 중요성

키는 리스트의 각 요소가 고유함을 보장하여 렌더링 성능을 최적화합니다. React는 키를 기반으로 요소가 변경되었는지를 판단하므로, 리스트의 순서가 바뀌거나 항목이 추가되고 삭제되는 경우에 중요한 역할을 합니다.

            
{`const colors = ['빨간색', '파란색', '초록색'];

function ColorList() {
    return (
        
    {colors.map(color => (
  • {color}
  • ))}
); }`}

위의 예제에서 각 색상 이름을 키로 사용했습니다. 이는 리스트의 항목이 고유하다는 것을 보장합니다.

동적 리스트 업데이트

React에서는 상태(state)를 이용하여 리스트를 동적으로 업데이트할 수 있습니다. 예를 들어, 사용자가 리스트에 새 항목을 추가하는 기능을 만들어볼 수 있습니다.

            
{`import React, { useState } from 'react';

function ItemList() {
    const [items, setItems] = useState(['item 1', 'item 2']);
    const [inputValue, setInputValue] = useState('');

    const addItem = () => {
        setItems([...items, inputValue]);
        setInputValue('');
    };

    return (
        
setInputValue(e.target.value)} placeholder="새 항목 입력" />
    {items.map((item, index) => (
  • {item}
  • ))}
); }`}

위의 예제는 사용자가 입력한 새로운 항목을 리스트에 추가하는 방법을 보여줍니다. useState 훅을 사용해 상태를 관리하며, 입력창과 버튼을 통해 동적인 업데이트를 구현했습니다.

결론

JSX와 React 요소는 React의 근본적인 개념으로, 이 둘을 이해하는 것은 React 개발의 첫걸음입니다. 리스트와 키를 사용한 반복 렌더링을 통해 동적인 UI를 구현할 수 있으며, React의 강력한 기능을 더욱 잘 활용할 수 있습니다. 이 글이 React에 대한 이해를 깊이 하는 데 도움이 되었기를 바랍니다.

더 나아가 React의 상태 관리와 라이프사이클 메소드, 다양한 컴포넌트 디자인 패턴에 대해서도 탐구해보는 것도 좋습니다. React는 계속해서 진화하는 라이브러리이므로, 최신 경향과 베스트 프랙티스를 지속적으로 학습하는 것이 중요합니다. Happy Coding!

커스텀 마커 및 정보창 만들기, 마커 클릭 시 팝업 정보창 표시하기

이번 포스트에서는 리액트 애플리케이션에서 구글 맵 API를 사용하여 커스텀 마커와 정보창을 만들어보겠습니다. 사용자가 마커를 클릭했을 때 팝업 형태로 정보를 표시하는 기능을 구현해볼 것입니다. 이를 통해 지도 애플리케이션을 더욱 풍부하게 만들 수 있습니다.

준비하기

우선, 구글 맵을 사용할 수 있도록 준비가 필요합니다. 다음 단계를 따라 구글 API 키를 생성해 주세요:

  1. 구글 클라우드 플랫폼에 로그인합니다.
  2. 새 프로젝트를 생성합니다.
  3. API 및 서비스 > 라이브러리에서 ‘Maps JavaScript API’를 검색하고 활성화합니다.
  4. API 및 서비스 > 사용자 인증 정보에서 ‘API 키’를 생성합니다.

리액트 애플리케이션 생성

리액트 애플리케이션을 생성하려면, 아래의 명령을 터미널에 입력합니다.

npx create-react-app my-maps-app

이제 애플리케이션 폴더로 이동합니다.

cd my-maps-app

구글 맵 API 설치

구글 맵 API를 사용하기 위해 react-google-maps/api 패키지를 설치합니다. 터미널에 아래의 명령어를 입력하세요:

npm install @react-google-maps/api

기본 맵 컴포넌트 만들기

src 폴더 아래에 Map.js 파일을 생성하고, 기본적인 맵 컴포넌트를 구성합니다.


import React from 'react';
import { GoogleMap, LoadScript } from '@react-google-maps/api';

const mapContainerStyle = {
    width: '100%',
    height: '400px'
};

const center = {
    lat: 37.5665,
    lng: 126.978
};

const Map = () => {
    return (
        
            
                {/* 마커와 정보창은 여기서 추가할 것입니다 */}
            
        
    );
};

export default Map;

위 코드에서 YOUR_API_KEY를 구글 클라우드 플랫폼에서 발급받은 API 키로 교체하세요.

커스텀 마커 추가하기

이제 커스텀 마커를 추가해보겠습니다. 앞서 작성한 Map 컴포넌트에 MarkerInfoWindow를 추가합니다.


import React, { useState } from 'react';
import { GoogleMap, LoadScript, Marker, InfoWindow } from '@react-google-maps/api';

const mapContainerStyle = {
    width: '100%',
    height: '400px'
};

const center = {
    lat: 37.5665,
    lng: 126.978
};

const Map = () => {
    const [selected, setSelected] = useState(null);

    const markers = [
        {
            id: 1,
            name: '서울시청',
            position: { lat: 37.5665, lng: 126.978 },
            info: '서울특별시 중구 세종대로 110'
        },
        {
            id: 2,
            name: '남산타워',
            position: { lat: 37.5512, lng: 126.9882 },
            info: '서울특별시 용산구 남산공원길 105'
        }
    ];

    return (
        
            
                {markers.map(marker => (
                     setSelected(marker)}
                    />
                ))}
                
                {selected && (
                     setSelected(null)}
                    >
                        

{selected.name}

{selected.info}

)}
); }; export default Map;

컴포넌트 통합하기

이제 Map 컴포넌트를 App.js에서 사용해보겠습니다. src/App.js 파일을 열고 아래와 같이 수정하세요:


import React from 'react';
import './App.css';
import Map from './Map';

const App = () => {
    return (
        

리액트 커스텀 마커 만들기 예제

); }; export default App;

결과 확인하기

모든 준비가 완료되었습니다. 이제 애플리케이션을 실행해보겠습니다. 터미널에 아래의 명령어를 입력하세요:

npm start

브라우저에서 http://localhost:3000으로 이동하면 구현한 구글 맵과 커스텀 마커가 나타나는 것을 확인할 수 있습니다. 마커를 클릭하면 정보창이 표시됩니다.

결론

이번 포스트에서는 리액트에서 구글 맵 API를 활용해 커스텀 마커 및 정보창을 만드는 방법에 대해 알아보았습니다. 마커를 클릭할 때마다 다양한 정보를 표시할 수 있도록 구성하여, 여러분의 애플리케이션을 더 인터랙티브하게 만들 수 있습니다. 앞으로도 구글 맵 API를 이용해 더욱 다양한 기능을 추가해보길 바랍니다.

부록: 추가 기능 아이디어

  • 사용자 위치 기반 마커 표시하기
  • 다양한 아이콘 사용하기 (마커의 디자인 변경)
  • 마커 클러스터링 사용하기

추가로 다양한 기능을 구현함으로써, 애플리케이션에 더 많은 가치를 부여해보세요.

고급 상태 관리 Redux 사용하기, 액션과 리듀서를 사용한 상태 변경

React는 컴포넌트 기반의 사용자 인터페이스를 구축하는 데 매우 효율적입니다. 그러나 애플리케이션이 복잡해짐에 따라 상태 관리는 더욱 어려워질 수 있습니다. 이럴 때 Redux와 같은 상태 관리 라이브러리를 사용하는 것이 유용합니다. Redux는 전역 상태를 중앙 집중식으로 관리하는 라이브러리로, 복잡한 React 애플리케이션에서 상태를 예측 가능하게 유지할 수 있게 도와줍니다. 이번 글에서는 Redux를 사용하여 상태를 관리하는 방법과 액션 및 리듀서를 통한 상태 변경에 관해 자세히 설명하겠습니다.

Redux란 무엇인가?

Redux는 JavaScript 애플리케이션에서 전역 상태를 관리하기 위한 라이브러리입니다. 애플리케이션의 모든 상태를 하나의 중앙 저장소(store)에 보관하며, 이 저장소는 액션(action)을 통해 상태를 업데이트합니다. Redux를 사용하면 애플리케이션의 상태 변화가 일관되고 예측 가능해지며, 유지보수와 디버깅이 쉬워집니다.

Redux의 주요 개념

  • Store: 애플리케이션의 상태를 저장하는 객체입니다. Redux에서는 오직 하나의 Store만을 사용합니다.
  • Action: 상태 변화의 목적을 설명하는 객체입니다. Action은 type 속성을 반드시 가져야 하며, 필요에 따라 추가적인 데이터를 포함할 수 있습니다.
  • Reducer: 현재 상태와 액션을 인수로 받아 새로운 상태를 반환하는 순수 함수입니다. Reducer는 상태를 변경하는 로직을 포함하고 있습니다.

Redux 설치 및 기본 설정

Redux를 설치하려면, npm 또는 yarn을 사용할 수 있습니다. 아래 명령어를 통해 Redux 및 React-Redux를 설치합니다.

npm install redux react-redux

프로젝트 구조 설정

간단한 Todo 앱의 예제를 통해 Redux를 어떻게 사용하는지 보여드리겠습니다. 아래와 같은 프로젝트 구조를 설정합니다.


my-todo-app/
|-- src/
|   |-- components/
|   |   |-- TodoList.js
|   |   |-- TodoItem.js
|   |-- actions/
|   |   |-- todoActions.js
|   |-- reducers/
|   |   |-- todoReducer.js
|   |-- store/
|   |   |-- store.js
|   |-- App.js
|   |-- index.js

액션(Action) 정의하기

액션은 상태를 업데이트하기 위한 “신호”입니다. 액션에는 반드시 type 속성이 있어야 하며, 추가적인 데이터(payload)를 가질 수 있습니다. 아래는 Todo와 관련된 액션들을 정의한 todoActions.js입니다.


// src/actions/todoActions.js

export const ADD_TODO = 'ADD_TODO';
export const REMOVE_TODO = 'REMOVE_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';

export const addTodo = (todo) => ({
    type: ADD_TODO,
    payload: todo,
});

export const removeTodo = (id) => ({
    type: REMOVE_TODO,
    payload: id,
});

export const toggleTodo = (id) => ({
    type: TOGGLE_TODO,
    payload: id,
});

리듀서(Reducer) 정의하기

리듀서는 액션을 처리하여 새로운 상태를 반환하는 순수 함수입니다. 아래는 Todo 리듀서의 구현 예시입니다.


// src/reducers/todoReducer.js

import { ADD_TODO, REMOVE_TODO, TOGGLE_TODO } from '../actions/todoActions';

const initialState = {
    todos: [],
};

const todoReducer = (state = initialState, action) => {
    switch (action.type) {
        case ADD_TODO:
            return {
                ...state,
                todos: [...state.todos, { id: Date.now(), text: action.payload, completed: false }],
            };
        case REMOVE_TODO:
            return {
                ...state,
                todos: state.todos.filter(todo => todo.id !== action.payload),
            };
        case TOGGLE_TODO:
            return {
                ...state,
                todos: state.todos.map(todo =>
                    todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo
                ),
            };
        default:
            return state;
    }
};

export default todoReducer;

스토어(Store) 설정하기

Redux에서 스토어는 애플리케이션의 상태를 저장하고 액션을 디스패치하는 역할을 합니다. 아래는 스토어 설정을 위한 예제입니다.


// src/store/store.js

import { createStore } from 'redux';
import todoReducer from '../reducers/todoReducer';

const store = createStore(todoReducer);

export default store;

React 앱과 Redux 연동하기

React 애플리케이션에 Redux 스토어를 연결하기 위해서는 Provider 컴포넌트를 사용해야 합니다. Provider 컴포넌트는 애플리케이션 최상위에서 Redux의 스토어를 전달합니다.


// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store/store';
import App from './App';

ReactDOM.render(
    
        
    ,
    document.getElementById('root')
);

컴포넌트에서 Redux 상태와 액션 사용하기

이제 Redux 스토어를 React 컴포넌트와 연결하여 상태를 읽고 액션을 디스패치할 수 있습니다. 아래는 Todo 리스트를 구현한 컴포넌트입니다.


// src/components/TodoList.js

import React, { useState } from 'react';
import { connect } from 'react-redux';
import { addTodo, removeTodo, toggleTodo } from '../actions/todoActions';
import TodoItem from './TodoItem';

const TodoList = ({ todos, addTodo, removeTodo, toggleTodo }) => {
    const [inputValue, setInputValue] = useState('');

    const handleAddTodo = () => {
        if (inputValue) {
            addTodo(inputValue);
            setInputValue('');
        }
    };

    return (
        

Todo List

setInputValue(e.target.value)} />
    {todos.map(todo => ( ))}
); }; const mapStateToProps = (state) => ({ todos: state.todos, }); const mapDispatchToProps = { addTodo, removeTodo, toggleTodo, }; export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

TodoItem 컴포넌트 구현하기

아래는 개별 Todo 항목을 나타내는 컴포넌트입니다. 사용자가 Todo 항목을 클릭하면 완료 상태가 토글됩니다.


// src/components/TodoItem.js

import React from 'react';

const TodoItem = ({ todo, removeTodo, toggleTodo }) => {
    return (
        
  • {todo.text}
  • ); }; export default TodoItem;

    최종 결과

    위의 코드 구조를 통해 간단한 Todo 애플리케이션을 만들었습니다. Redux를 사용하여 상태를 중앙 집중식으로 관리하게 되면, 상태의 변화가 매우 명확해지고, 애플리케이션의 유지보수가 수월해집니다. 또한, Redux DevTools를 활용하면 상태 변화의 기록을 쉽게 추적할 수 있어 디버깅이 용이합니다.

    Redux의 장점과 단점

    장점

    • 예측 가능한 상태 관리: 상태의 변화가 특정 액션에 명확하게 연결됩니다.
    • 디버깅 용이: Redux DevTools를 통해 상태 변경을 추적할 수 있습니다.
    • 상태의 중앙 집중화: 여러 컴포넌트에서 동일한 상태에 접근할 수 있습니다.

    단점

    • 보일러플레이트 코드: 액션과 리듀서를 정의해야 하므로 코드 양이 증가합니다.
    • 학습 곡선: 초기 설정이 복잡할 수 있으며, Redux의 개념을 이해하는 데 시간이 필요합니다.

    결론

    Redux는 React 애플리케이션의 상태 관리를 위한 강력한 도구입니다. 본 글에서는 Redux의 기본 개념, 액션과 리듀서를 활용한 상태 변경, 그리고 React와의 결합 방법을 설명했습니다. 실제 프로젝트에서 Redux를 사용하면 상태 관리가 훨씬 수월해지며, 애플리케이션의 구조를 더욱 효율적으로 유지할 수 있습니다.

    앞으로도 Redux와 관련된 고급 기능들, 예를 들어 미들웨어, 비동기 작업 처리 등을 다룰 예정이니 관심을 가지고 지켜봐 주시기 바랍니다.

    폼과 사용자 입력 처리, 사용자 입력 검증 및 유효성 검사

    1. 리액트에서의 폼 기초

    리액트는 선언적 방식으로 사용자 인터페이스(UI)를 구성할 수 있게 해주는 라이브러리입니다. 사용자 입력을 처리하기 위해 폼을 작성하는 것이 일반적이며, 이는 다양한 입력 요소를 통해 사용자와의 상호작용을 가능하게 합니다. 리액트에서는 폼을 간단히 관리할 수 있는 방법을 제공합니다.

    1.1. 기본 폼 요소

    리액트에서 사용되는 기본 폼 요소에는 <input>, <textarea>, <select>가 있으며, 각각의 요소는 사용자 입력을 받는 역할을 합니다.

    
    function MyForm() {
        return (
            
    ); }

    2. 사용자 입력 처리

    사용자 입력을 처리하는 것은 웹 애플리케이션에서 매우 중요한 부분입니다. 리액트에서는 상태(state)를 사용하여 사용자 입력을 실시간으로 관리할 수 있습니다. 이를 위해 상태를 정의하고, 이벤트 핸들러를 통해 상호작용을 처리합니다.

    2.1. 상태 관리

    리액트의 상태를 사용하여 폼의 입력값을 저장할 수 있습니다. 이를 통해 사용자가 입력하는 값에 대한 실시간 피드백을 제공할 수 있습니다.

    
    import React, { useState } from 'react';
    
    function MyForm() {
        const [name, setName] = useState('');
        const [message, setMessage] = useState('');
    
        const handleNameChange = (event) => {
            setName(event.target.value);
        };
    
        const handleMessageChange = (event) => {
            setMessage(event.target.value);
        };
    
        const handleSubmit = (event) => {
            event.preventDefault();
            alert(`이름: ${name}, 메시지: ${message}`);
        };
    
        return (
            
    ); }

    3. 사용자 입력 검증

    사용자 입력 검증은 웹 애플리케이션의 안정성과 보안을 높이는 데 매우 중요합니다. 이를 통해 잘못된 입력을 사전에 방지하고, 사용자에게 적절한 피드백을 줄 수 있습니다.

    3.1. 필수 입력 항목 검증

    필수 입력 항목이 비어 있는 경우 경고 메시지를 출력하는 간단한 검증 로직을 추가할 수 있습니다.

    
    const handleSubmit = (event) => {
        event.preventDefault();
        if (!name || !message) {
            alert('모든 필드를 입력해야 합니다.');
            return;
        }
        alert(`이름: ${name}, 메시지: ${message}`);
    };
                

    4. 유효성 검사

    사용자 입력에 대한 유효성 검사는 특정 형식이나 조건을 만족하는지를 확인하는 과정입니다. 예를 들어, 이메일 주소 형식이 올바른지 확인하는 검증을 추가할 수 있습니다.

    4.1. 이메일 형식 검사

    
    const [email, setEmail] = useState('');
    
    const handleEmailChange = (event) => {
        setEmail(event.target.value);
    };
    
    const handleSubmit = (event) => {
        event.preventDefault();
        if (!/\S+@\S+\.\S+/.test(email)) {
            alert('유효한 이메일 주소를 입력하세요.');
            return;
        }
        alert(`이메일: ${email}`);
    };
    
    return (
        
    );

    5. 커스텀 훅을 이용한 입력 검증

    입력 검증 로직을 더욱 깔끔하게 관리하기 위해 커스텀 훅을 사용할 수 있습니다. 이를 통해 중복 코드를 줄이고 유지 보수를 용이하게 할 수 있습니다.

    
    import { useState } from 'react';
    
    function useInput(initialValue, validate) {
        const [value, setValue] = useState(initialValue);
        const [isValid, setIsValid] = useState(true);
    
        const handleChange = (event) => {
            setValue(event.target.value);
            setIsValid(validate(event.target.value));
        };
    
        return {
            value,
            onChange: handleChange,
            isValid,
        };
    }
    
    function MyForm() {
        const email = useInput('', (value) => /\S+@\S+\.\S+/.test(value));
    
        const handleSubmit = (event) => {
            event.preventDefault();
            if (!email.isValid) {
                alert('유효한 이메일 주소를 입력하세요.');
                return;
            }
            alert(`이메일: ${email.value}`);
        };
    
        return (
            
    ); }

    6. 비동기 검증

    사용자 입력 검증이 비동기적일 경우, 예를 들어 서버에서 이메일 중복 여부를 체크해야 하는 경우가 있습니다. 이 경우, 비동기 방식으로 검증할 수 있습니다.

    
    const handleEmailChange = async (event) => {
        setEmail(event.target.value);
        const response = await fetch(`/api/check-email?email=${event.target.value}`);
        const { isAvailable } = await response.json();
        setIsValid(isAvailable);
    };
                

    7. 폼 제출 후 처리

    폼 제출 후에는 사용자에게 피드백을 제공하거나, 다른 페이지로 이동하는 등의 처리가 필요합니다. 이를 위해 상태를 관리합니다.

    
    const handleSubmit = async (event) => {
        event.preventDefault();
        if (!email.isValid) {
            alert('유효한 이메일 주소를 입력하세요.');
            return;
        }
        const response = await fetch('/api/submit', {
            method: 'POST',
            body: JSON.stringify({ email: email.value }),
        });
        if (response.ok) {
            alert('폼이 성공적으로 제출되었습니다.');
        }
    };
                

    8. 결론

    리액트에서의 폼과 사용자 입력 처리, 검증 및 유효성 검사는 웹 애플리케이션의 중요한 부분입니다. 적절한 입력 처리는 사용자 경험을 향상시키고, 애플리케이션의 신뢰성을 높이는 데 기여합니다. 이번 강좌에서 다룬 내용들을 바탕으로 다양한 폼을 구현해보시기 바랍니다.

    리액트에서 표 구현하기, 리액트 기본 테이블 컴포넌트 구성하기

    웹 애플리케이션에서 데이터를 시각적으로 표현하는 방법 중 하나는 ‘표(table)’입니다. 특히 대량의 데이터를 다룰 때, 표는 정보를 체계적으로 정리하여 사용자에게 제공하는 효과적인 방법입니다. 이번 글에서는 리액트에서 표를 어떻게 구현할 수 있는지에 대해 알아보겠습니다.

    1. 리액트와 표의 간단한 이해

    리액트는 UI를 구성하는데 필요한 요소들을 컴포넌트라는 단위로 나누어 관리합니다. 컴포넌트는 재사용 가능하고, 서로 독립적으로 작동할 수 있습니다. 오늘은 기본적인 테이블 컴포넌트를 구성하고, 이를 통해 데이터 배열을 시각적으로 표현하는 방법을 살펴보겠습니다.

    2. 리액트 테이블 컴포넌트 설계

    테이블을 구성하기 위해 먼저 기본적인 구조를 설계해야 합니다. 리액트에서는 컴포넌트를 설계할 때, 어떤 속성(props)을 받을지를 결정하고 각 열(column)과 행(row)을 어떻게 구성할지를 명시해야 합니다.

    2.1 테이블 컴포넌트의 기본 구조

                
                import React from 'react';
    
                const Table = ({ data, columns }) => {
                    return (
                        
                                    {columns.map((col) => (
                                        
                                    ))}
                                
                                {data.map((row, index) => (
                                    
                                        {columns.map((col) => (
                                            
                                        ))}
                                    
                                ))}
                            
    {col.title}
    {row[col.dataIndex]}
    ); }; export default Table;

    위 코드는 기본적인 테이블 컴포넌트를 정의하는 예시입니다. 여기서 `data`는 표에 표시할 데이터 배열이고, `columns`는 각 열의 제목과 데이터 키를 포함한 배열입니다.

    3. 데이터 및 열 구성하기

    이제 실질적으로 사용할 데이터와 열을 정의해보겠습니다. 예를 들어, 학생 정보를 나타내는 테이블을 가정해보겠습니다.

                
                const data = [
                    { id: 1, name: '홍길동', age: 20 },
                    { id: 2, name: '김철수', age: 22 },
                    { id: 3, name: '이영희', age: 21 },
                ];
    
                const columns = [
                    { key: 'id', title: '학생 ID', dataIndex: 'id' },
                    { key: 'name', title: '이름', dataIndex: 'name' },
                    { key: 'age', title: '나이', dataIndex: 'age' },
                ];
                
                

    이 데이터와 열 구성을 가지고, 앞서 만든 테이블 컴포넌트를 사용하여 학생 목록을 표현해봅니다.

    3.1 테이블 컴포넌트 사용 예시

                
                import React from 'react';
                import Table from './Table';
    
                const App = () => {
                    return (
                        

    학생 목록

    ); }; export default App;

    위 코드는 `App` 컴포넌트로, `Table` 컴포넌트를 사용하여 학생 목록을 표현합니다. 위 예제에서는 `data`와 `columns`가 각기 테이블 컴포넌트에 props로 전달됩니다.

    4. 테이블 스타일링

    자바스크립트 및 CSS를 활용하여 테이블을 꾸미는 방법에 대해 알아보겠습니다. 먼저 기본적인 CSS 스타일을 만듭니다.

                
                table {
                    width: 100%;
                    border-collapse: collapse;
                }
    
                th, td {
                    border: 1px solid #ccc;
                    padding: 8px;
                    text-align: left;
                }
    
                th {
                    background-color: #f2f2f2;
                }
                
                

    위의 CSS 스타일 코드를 추가하면, 테이블이 더 보기 좋은 형태로 디자인됩니다. 테이블의 경계가 선명해지고, 헤더 부분은 강조되어 보입니다.

    5. 기능적인 테이블 만들기

    이제 기능적인 테이블을 만들어 보겠습니다. 예를 들어, 데이터 정렬 기능과 페이지네이션 기능을 추가해보겠습니다.

    5.1 데이터 정렬 기능 추가하기

    데이터를 클릭하여 정렬하는 기능을 구현할 수 있습니다. `Table` 컴포넌트에 정렬기능을 추가해 보겠습니다.

                
                import React, { useState } from 'react';
    
                const Table = ({ data, columns }) => {
                    const [sortConfig, setSortConfig] = useState(null);
    
                    const sortedData = React.useMemo(() => {
                        let sortableItems = [...data];
                        if (sortConfig !== null) {
                            sortableItems.sort((a, b) => {
                                if (a[sortConfig.key] < b[sortConfig.key]) {
                                    return sortConfig.direction === 'ascending' ? -1 : 1;
                                }
                                if (a[sortConfig.key] > b[sortConfig.key]) {
                                    return sortConfig.direction === 'ascending' ? 1 : -1;
                                }
                                return 0;
                            });
                        }
                        return sortableItems;
                    }, [data, sortConfig]);
    
                    const requestSort = (key) => {
                        let direction = 'ascending';
                        if (sortConfig && sortConfig.key === key && sortConfig.direction === 'ascending') {
                            direction = 'descending';
                        }
                        setSortConfig({ key, direction });
                    };
    
                    return (
                        
                                    {columns.map((col) => (
                                        
                                    ))}
                                
                                {sortedData.map((row, index) => (
                                    
                                        {columns.map((col) => (
                                            
                                        ))}
                                    
                                ))}
                            
    requestSort(col.dataIndex)}> {col.title}
    {row[col.dataIndex]}
    ); }; export default Table;

    위 코드는 정렬 기능을 추가한 `Table` 컴포넌트입니다. 각 열의 헤더를 클릭함으로써 해당 키를 기준으로 오름차순 또는 내림차순으로 정렬할 수 있습니다.

    5.2 페이지네이션 기능 추가하기

    페이지네이션 기능은 데이터 세트가 너무 클 경우 유용합니다. 사용자는 한 번에 모든 데이터를 보는 것보다 적절한 페이지 수만큼 보여주는 것이 더 효율적입니다.

                
                const PaginatedTable = ({ data, columns, rowsPerPage }) => {
                    const [currentPage, setCurrentPage] = useState(0);
                    const pagesCount = Math.ceil(data.length / rowsPerPage);
    
                    const getData = () => {
                        const startIndex = currentPage * rowsPerPage;
                        return data.slice(startIndex, startIndex + rowsPerPage);
                    };
    
                    return (
                        
    {Array.from({ length: pagesCount }, (_, index) => ( ))}
    ); };

    위 코드는 페이지네이션 기능을 추가한 테이블입니다. `rowsPerPage`라는 변수를 통해 한 페이지에 표시할 행의 수를 조정할 수 있습니다. 페이지 버튼을 클릭하면 해당 페이지에 맞는 데이터를 가져와 테이블에 표시합니다.

    6. 결론

    오늘은 리액트에서 기본적인 테이블 컴포넌트를 구현하는 방법을 살펴보았습니다. 학생 데이터를 예로 들어 기본적인 템플릿을 만들고, 정렬 및 페이지네이션 기능을 추가하여 더 유용한 컴포넌트를 제공했습니다.

    이와 같은 테이블 구성은 다양한 데이터 표시 필요성이 있는 리액트 앱에서 매우 유용할 것입니다. 추가적으로 사용자의 입력에 따라 동적으로 변할 수 있는 테이블로 발전시킬 수 있습니다.

    향후에는 더 복잡한 테이블을 구성하고 데이터 필터링, 검색 기능 등의 고급 기능을 공부해 보는 것도 좋을 것입니다.