본문 바로가기
AI, 클라우드, 협업, 교육, 문서, 업무자동화

React 기본 사용법

by 아톨 2025. 7. 14.

React의 기본적인 동작 방식, React Router를 이용한 페이지 라우팅, 그리고 Redux Toolkit을 활용한 상태 관리 방법에 대해 상세히 설명합니다. 각 파일이 어떤 역할을 하는지 이해하시면 React 프로젝트의 구조와 흐름을 파악하는 데 도움이 될 것입니다.

1. index.js 파일 : React 앱의 시작점

index.js는 React 애플리케이션의 가장 첫 번째 진입점입니다. 웹 페이지의 HTML과 React 컴포넌트를 연결하고, 전역적으로 필요한 설정(라우터, 상태 관리 등)을 적용하는 역할을 합니다.

import React from 'react'; // React 라이브러리를 가져옵니다. JSX 문법을 사용하기 위해 필수적입니다.
import ReactDOM from 'react-dom/client'; // React DOM 라이브러리를 가져옵니다. 웹 브라우저 DOM과 React를 연결하는 데 사용됩니다.
import './index.css'; // 전역 CSS 파일을 가져옵니다. 앱 전체에 적용될 스타일을 정의합니다.
import App from './App'; // './App.js' 파일에 정의된 App 컴포넌트를 가져옵니다. 이 App 컴포넌트가 React 앱의 최상위 컴포넌트가 됩니다.
import reportWebVitals from './reportWebVitals'; // 웹 성능 측정을 위한 유틸리티 함수를 가져옵니다. (선택 사항)

import {BrowserRouter} from 'react-router-dom'; // React Router DOM 라이브러리에서 BrowserRouter 컴포넌트를 가져옵니다. 웹 애플리케이션의 URL을 관리하여 라우팅을 가능하게 합니다.

import {Provider} from 'react-redux'; // React Redux 라이브러리에서 Provider 컴포넌트를 가져옵니다. Redux 스토어를 React 컴포넌트 트리에 제공하여 모든 하위 컴포넌트가 스토어에 접근할 수 있도록 합니다.
import {store} from './redux/store'; // './redux/store.js' 파일에 정의된 Redux 스토어를 가져옵니다.

const root = ReactDOM.createRoot(document.getElementById('root')); // 웹 페이지의 'root'라는 ID를 가진 DOM 요소를 찾아 React 앱의 렌더링 시작점으로 지정합니다. React 18부터는 createRoot를 사용하여 더 나은 성능을 제공합니다.
root.render(
  <React.StrictMode> {/* React.StrictMode는 개발 모드에서 잠재적인 문제를 감지하기 위한 도구입니다. 프로덕션 빌드에는 영향을 미치지 않습니다. */}
    <BrowserRouter> {/* BrowserRouter는 HTML5 History API를 사용하여 URL을 동기화하고, SPA(Single Page Application)에서 페이지 이동 없이 URL 경로를 변경할 수 있도록 합니다. */}
      <Provider store={store}> {/* Provider는 Redux 스토어를 React 컴포넌트 트리에 주입하는 역할을 합니다. Provider 내부에 있는 모든 컴포넌트는 Redux 스토어의 상태에 접근하고 액션을 디스패치할 수 있습니다. */}
        <App /> {/* App 컴포넌트가 Provider와 BrowserRouter의 자식으로 렌더링됩니다. 즉, App 컴포넌트와 그 하위 컴포넌트들은 라우팅과 Redux 상태 관리를 사용할 수 있게 됩니다. */}
      </Provider>
    </BrowserRouter>

  </React.StrictMode>
);

// 웹 성능 측정을 위한 함수 호출입니다.
reportWebVitals();

다시 정리:

  • ReactDOM.createRoot(document.getElementById('root')): React 애플리케이션이 HTML 문서의 어느 부분에 마운트(렌더링)될지 결정합니다. 일반적으로 public/index.html 파일에 <div id="root"></div> 요소가 있습니다.
  • root.render(): React 컴포넌트를 실제 DOM에 렌더링하는 역할을 합니다.
  • React.StrictMode: 개발 모드에서만 동작하며, 잠재적인 버그나 성능 문제를 감지하는 데 도움을 줍니다.
  • BrowserRouter: 웹 애플리케이션의 URL 경로를 관리하여 SPA(Single Page Application)에서 페이지 전환 없이 URL만 변경될 수 있도록 합니다.
  • Provider (from react-redux): Redux 스토어를 React 컴포넌트 트리의 모든 자식 컴포넌트가 접근할 수 있도록 제공하는 역할을 합니다.

2. App.js 파일 : 메인 애플리케이션 컴포넌트와 라우팅

App.js는 React 애플리케이션의 최상위 컴포넌트이며, 주로 전역적인 레이아웃을 구성하거나 라우팅을 정의하는 데 사용됩니다.

import logo from './logo.svg'; // 로고 이미지를 가져옵니다. (사용되지 않음)
import './App.css'; // App 컴포넌트의 스타일을 정의하는 CSS 파일을 가져옵니다.

import {Routes, Route} from 'react-router-dom'; // React Router DOM에서 Routes와 Route 컴포넌트를 가져옵니다. 라우팅 정의에 사용됩니다.

import Test1Page from './test1page'; // './test1page/index.jsx' 파일에 정의된 Test1Page 컴포넌트를 가져옵니다.
import Test2Page from './test2page'; // './test2page/index.jsx' 파일에 정의된 Test2Page 컴포넌트를 가져옵니다.


// Routes 컴포넌트는 라우팅을 정의하는 컴포넌트입니다.
// Route 컴포넌트는 각각의 경로와 해당 경로에 렌더링할 컴포넌트를 정의합니다.
// path 속성은 URL 경로를 정의하고, element 속성은 해당 경로에 렌더링할 컴포넌트를 지정합니다.
// '/' 경로는 기본 경로로, 이 경로에 접근하면 Test1Page 컴포넌트가 렌더링됩니다. 홈페이지입니다.
// '/' 요청이 오면, Test1Page를 보여준다는 의미입니다.
function App() { // App이라는 이름의 함수형 컴포넌트를 정의합니다. React 컴포넌트는 대문자로 시작해야 합니다.
  return ( // 컴포넌트가 렌더링할 JSX(JavaScript XML)를 반환합니다.
    <div> {/* 모든 JSX는 하나의 부모 요소로 감싸져야 합니다. 여기서는 <div>를 사용했습니다. */}
      <Routes> {/* Routes 컴포넌트는 여러 Route 컴포넌트들을 감싸며, 현재 URL 경로와 일치하는 첫 번째 Route를 렌더링합니다. */}
        <Route path='/' element={<Test1Page/>}> </Route> {/* URL 경로가 '/'일 때 Test1Page 컴포넌트를 렌더링합니다. 이는 웹사이트의 기본 또는 홈 페이지가 됩니다. */}
        <Route path='/test' element={<Test2Page/>}></Route> {/* URL 경로가 '/test'일 때 Test2Page 컴포넌트를 렌더링합니다. */}
      </Routes>

    </div>
  );
}

export default App; // App 컴포넌트를 외부(index.js)에서 가져다 사용할 수 있도록 내보냅니다.

다시 정리:

  • 함수형 컴포넌트: function App() { ... } 형태로 정의된 컴포넌트입니다. React 훅(Hooks)과 함께 현대 React 개발에서 주로 사용됩니다.
  • JSX: JavaScript 안에 HTML과 유사한 마크업을 작성할 수 있게 해주는 문법 확장입니다. <div>, <Routes>, <Route> 등이 JSX 요소입니다.
  • Routes (from react-router-dom): 여러 Route 컴포넌트들을 감싸는 컨테이너입니다. 현재 URL과 일치하는 Route를 찾아 렌더링합니다.
  • Route (from react-router-dom): 특정 path (URL 경로)에 접근했을 때 어떤 element (React 컴포넌트)를 보여줄지 정의합니다.

3. redux/counterSlice.js 파일 : Redux Toolkit의 Slice

counterSlice.js 파일은 Redux Toolkit의 createSlice 함수를 사용하여 Redux 상태(state)의 일부(slice)와 해당 상태를 변경하는 리듀서(reducer) 및 액션(action)을 한 번에 정의합니다.

import {createSlice} from "@reduxjs/toolkit"; // Redux Toolkit에서 createSlice 함수를 가져옵니다.

const counterSlice = createSlice({ // createSlice 함수를 호출하여 새로운 Redux 슬라이스를 생성합니다.
    name: 'counter', // 이 슬라이스의 이름을 정의합니다. 액션 타입 접두사로 사용됩니다 (예: 'counter/increment').
    initialState:{ // 이 슬라이스의 초기 상태(state)를 정의합니다.
        value:0 // 'counter' 슬라이스의 초기 상태는 'value'가 0인 객체입니다.
    },
    reducers:{ // 상태를 변경하는 함수들을 정의합니다. 이 함수들은 '액션 타입'과 '리듀서' 역할을 동시에 수행합니다.
        increment: (state) => { // 'increment'라는 리듀서 함수를 정의합니다. 액션 타입은 'counter/increment'가 됩니다.
            state.value = state.value +1; // Redux Toolkit은 Immer 라이브러리를 내장하고 있어, 상태를 직접 변경하는 것처럼 보이는 코드를 작성해도 내부적으로는 불변성(immutability)을 유지합니다. (뮤테이션처럼 보이지만 실제로는 새로운 상태를 반환)
        },
        decrement: (state) => { // 'decrement'라는 리듀서 함수를 정의합니다. 액션 타입은 'counter/decrement'가 됩니다.
            state.value = state.value -1; // 'value'를 1 감소시킵니다.
        }
    }
})

export const {increment, decrement} = counterSlice.actions; // counterSlice.actions에서 'increment'와 'decrement' 액션 생성자 함수를 추출하여 외부로 내보냅니다. 이 함수들을 호출하면 해당 액션 객체가 생성됩니다.
export default counterSlice.reducer; // counterSlice.reducer는 이 슬라이스에 정의된 모든 리듀서 함수들을 결합한 최종 리듀서 함수입니다. 이 리듀서를 Redux 스토어에 등록합니다.

다시 정리 :

  • Redux Toolkit: Redux 개발을 더 쉽고 효율적으로 만들어주는 공식 도구 모음입니다.
  • createSlice: Redux Toolkit의 핵심 함수로, 상태 이름(name), 초기 상태(initialState), 그리고 상태를 변경하는 리듀서 함수들(reducers)을 한 번에 정의할 수 있게 해줍니다. 액션 타입, 액션 생성자, 리듀서 로직을 자동으로 생성해 줍니다.
  • name: 슬라이스의 고유 이름으로, 생성되는 액션 타입의 접두사로 사용됩니다 (예: counter/increment).
  • initialState: 해당 슬라이스의 초기 상태 값입니다.
  • reducers: 상태를 변경하는 로직을 담은 함수들입니다. 이 함수들은 stateaction 객체를 인자로 받습니다. Redux Toolkit 덕분에 state.value = state.value + 1처럼 직접 상태를 변경하는 것처럼 코드를 작성해도 불변성이 유지됩니다 (내부적으로 Immer 라이브러리 사용).
  • 액션 생성자 (counterSlice.actions): createSlice가 자동으로 생성해 주는 함수들로, 이 함수들을 호출하면 해당 액션 객체(예: { type: 'counter/increment' })가 반환됩니다.
  • 리듀서 (counterSlice.reducer): createSlice가 생성하는 최종 리듀서 함수로, Redux 스토어에 등록되어 액션에 따라 상태를 변경합니다.

4. redux/store.js 파일 : Redux 스토어 설정

store.js 파일은 Redux 애플리케이션의 중앙 저장소인 스토어(Store)를 생성하고 설정합니다.

import {configureStore} from "@reduxjs/toolkit"; // Redux Toolkit에서 configureStore 함수를 가져옵니다. 스토어를 생성하는 데 사용됩니다.

import counterReducer from './counterSlice'; // './counterSlice.js' 파일에서 내보낸 기본 리듀서(counterSlice.reducer)를 'counterReducer'라는 이름으로 가져옵니다.

export const store = configureStore({ // configureStore 함수를 호출하여 Redux 스토어를 생성하고 설정합니다.
    reducer: { // 'reducer' 속성에는 애플리케이션의 모든 리듀서들을 객체 형태로 정의합니다.
        // key: value 형태로, 'key'는 상태 트리의 해당 부분의 이름이 되고, 'value'는 해당 부분을 관리하는 리듀서 함수입니다.
        counter: counterReducer // 'counter'라는 이름으로 'counterReducer'를 등록합니다. 이제 Redux 스토어의 상태는 store.counter.value와 같이 접근할 수 있게 됩니다.
    }
})

다시 정리 :

  • configureStore (from reduxjs/toolkit): Redux 스토어를 생성하는 가장 권장되는 방법입니다. 여러 리듀서를 자동으로 결합하고, Redux DevTools 확장 프로그램 설정, 미들웨어 추가 등 복잡한 스토어 설정을 간소화합니다.
  • reducer: configureStore의 핵심 옵션입니다. 애플리케이션의 전체 상태 트리를 구성하는 리듀서들을 객체 형태로 받습니다. 각 키는 상태 트리의 해당 부분의 이름이 되고, 값은 그 부분을 관리하는 리듀서 함수입니다.
  • store: configureStore에 의해 생성된 최종 Redux 스토어 객체입니다. 이 스토어는 index.jsProvider 컴포넌트에 전달되어 React 앱 전체에서 사용될 수 있게 됩니다.

5. test1page/index.jsx 파일 : React 컴포넌트 예시

React 컴포넌트는 일반적으로 JSX를 반환하며, Redux 상태를 사용한다면 useSelectoruseDispatch 훅을 사용합니다.

아래는 Test1Page가 Redux counter 상태를 읽고 변경하는 간단한 예시입니다.

import React from "react"; // React 라이브러리를 가져옵니다.
import { useSelector, useDispatch } from "react-redux"; // React Redux 훅인 useSelector와 useDispatch를 가져옵니다.
import { increment, decrement } from "../redux/counterSlice"; // Redux 슬라이스에서 정의한 액션 생성자들을 가져옵니다.

const Test1Page = () => { // Test1Page라는 함수형 컴포넌트를 정의합니다.
    // useSelector 훅을 사용하여 Redux 스토어의 상태에서 'counter' 슬라이스의 'value'를 가져옵니다.
    // 이제 'count' 변수는 Redux 스토어의 'counter.value'와 동기화됩니다.
    const count = useSelector((state) => state.counter.value);
    // useDispatch 훅을 사용하여 Redux 스토어에 액션을 디스패치할 수 있는 'dispatch' 함수를 가져옵니다.
    const dispatch = useDispatch();

    return ( // 컴포넌트가 렌더링할 JSX를 반환합니다.
        <div style={{ padding: '20px', textAlign: 'center' }}>
            <h1>Test1Page 입니다 (홈페이지)</h1>
            <p>현재 카운트: {count}</p> {/* Redux 스토어에서 가져온 'count' 값을 표시합니다. */}
            <button
                onClick={() => dispatch(increment())} // 버튼 클릭 시 'increment' 액션을 디스패치합니다.
                style={{ margin: '5px', padding: '10px 20px', fontSize: '16px', cursor: 'pointer' }}
            >
                증가
            </button>
            <button
                onClick={() => dispatch(decrement())} // 버튼 클릭 시 'decrement' 액션을 디스패치합니다.
                style={{ margin: '5px', padding: '10px 20px', fontSize: '16px', cursor: 'pointer' }}
            >
                감소
            </button>
            <p style={{ marginTop: '20px' }}>
                이 페이지는 Redux 상태 관리 예시를 보여줍니다.<br />
                `/test` 경로로 이동하면 다른 페이지를 볼 수 있습니다.
            </p>
        </div>
    );
}

export default Test1Page; // Test1Page 컴포넌트를 외부로 내보냅니다.

핵심 개념:

  • useSelector (from react-redux): Redux 스토어의 상태에서 필요한 부분을 선택하여 가져오는 훅입니다. 스토어 상태가 변경되면 컴포넌트가 자동으로 리렌더링됩니다.
  • useDispatch (from react-redux): Redux 스토어에 액션을 디스패치(발송)할 수 있는 dispatch 함수를 반환하는 훅입니다. 이 함수를 사용하여 리듀서를 통해 상태를 변경합니다.
  • JSX 반환: React 컴포넌트는 최종적으로 화면에 표시될 UI를 JSX 형태로 반환합니다.
  • 이벤트 핸들러 (onClick): HTML 요소의 이벤트(예: 클릭)가 발생했을 때 실행될 함수를 지정합니다.

6. test2page/index.jsx 파일 : 간단한 React 컴포넌트

test2page/index.jsx는 가장 기본적인 형태의 함수형 React 컴포넌트를 보여줍니다.

import React from "react"; // React 라이브러리를 가져옵니다. JSX 문법 사용을 위해 필요합니다.

const Test2Page = () => { // Test2Page라는 이름의 함수형 컴포넌트를 정의합니다.
    /* logic 구현 */ // 이 부분에 컴포넌트의 상태 관리, 데이터 가져오기 등의 로직을 구현할 수 있습니다.
    return( // 컴포넌트가 렌더링할 JSX를 반환합니다.
        <div> {/* 단일 부모 요소로 감싸져야 합니다. */}
            Test2Page입니다~~~ {/* 화면에 표시될 텍스트입니다. */}
        </div>
    )
}

export default Test2Page; // Test2Page 컴포넌트를 외부(App.js)에서 가져다 사용할 수 있도록 내보냅니다.

다시 정리 :

  • 함수형 컴포넌트: const ComponentName = () => { ... } 형태로 정의되며, return 문 안에 JSX를 포함합니다.
  • export default: 이 파일을 가져다 쓰는 다른 파일에서 import ComponentName from './path' 형태로 가져올 수 있도록 합니다.

React 기본 사용법 요약

이 코드들을 통해 React의 기본적인 사용법을 정리하면 다음과 같습니다:

  1. 컴포넌트 기반 개발: 모든 UI는 독립적인 컴포넌트(함수형 컴포넌트)로 구성됩니다. 각 컴포넌트는 JSX를 반환하여 UI를 정의합니다.
  2. JSX: JavaScript 파일 내에서 HTML과 유사한 문법을 사용하여 UI를 선언적으로 작성합니다.
  3. 컴포넌트 트리: index.js에서 App 컴포넌트를 렌더링하고, App 컴포넌트가 다른 컴포넌트들을 포함하는 방식으로 UI가 계층적으로 구성됩니다.
  4. React Router: SPA(Single Page Application)에서 URL 경로에 따라 다른 컴포넌트를 보여주는 라우팅 기능을 제공합니다. (BrowserRouter, Routes, Route)
  5. Redux Toolkit: 애플리케이션의 전역 상태를 효율적으로 관리하기 위한 라이브러리입니다.
    • Store: 모든 상태가 저장되는 중앙 저장소입니다.
    • Slice: createSlice를 사용하여 상태의 일부(ex: counter), 액션 생성자, 리듀서를 한 번에 정의합니다.
    • Provider: Redux 스토어를 React 컴포넌트 트리에 주입하여 하위 컴포넌트들이 스토어에 접근할 수 있도록 합니다.
    • useSelector: 컴포넌트에서 Redux 스토어의 상태를 읽어올 때 사용합니다.
    • useDispatch: 컴포넌트에서 Redux 스토어에 액션을 보내 상태를 변경할 때 사용합니다.

이 해설이 React의 기본 개념을 이해하는 데 도움이 되기를 바랍니다.

반응형