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: 상태를 변경하는 로직을 담은 함수들입니다. 이 함수들은 state와 action 객체를 인자로 받습니다. 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.js의 Provider 컴포넌트에 전달되어 React 앱 전체에서 사용될 수 있게 됩니다.
5. test1page/index.jsx 파일 : React 컴포넌트 예시
React 컴포넌트는 일반적으로 JSX를 반환하며, Redux 상태를 사용한다면 useSelector와 useDispatch 훅을 사용합니다.
아래는 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의 기본적인 사용법을 정리하면 다음과 같습니다:
- 컴포넌트 기반 개발: 모든 UI는 독립적인 컴포넌트(함수형 컴포넌트)로 구성됩니다. 각 컴포넌트는 JSX를 반환하여 UI를 정의합니다.
- JSX: JavaScript 파일 내에서 HTML과 유사한 문법을 사용하여 UI를 선언적으로 작성합니다.
- 컴포넌트 트리: index.js에서 App 컴포넌트를 렌더링하고, App 컴포넌트가 다른 컴포넌트들을 포함하는 방식으로 UI가 계층적으로 구성됩니다.
- React Router: SPA(Single Page Application)에서 URL 경로에 따라 다른 컴포넌트를 보여주는 라우팅 기능을 제공합니다. (BrowserRouter, Routes, Route)
- Redux Toolkit: 애플리케이션의 전역 상태를 효율적으로 관리하기 위한 라이브러리입니다.
- Store: 모든 상태가 저장되는 중앙 저장소입니다.
- Slice: createSlice를 사용하여 상태의 일부(ex: counter), 액션 생성자, 리듀서를 한 번에 정의합니다.
- Provider: Redux 스토어를 React 컴포넌트 트리에 주입하여 하위 컴포넌트들이 스토어에 접근할 수 있도록 합니다.
- useSelector: 컴포넌트에서 Redux 스토어의 상태를 읽어올 때 사용합니다.
- useDispatch: 컴포넌트에서 Redux 스토어에 액션을 보내 상태를 변경할 때 사용합니다.
이 해설이 React의 기본 개념을 이해하는 데 도움이 되기를 바랍니다.
'AI, 클라우드, 협업, 교육, 문서, 업무자동화' 카테고리의 다른 글
AWS EC2에 프론트엔드 배포하기 (0) | 2025.07.14 |
---|---|
.env 파일을 AWS 인스턴스에 올리는 방법 (0) | 2025.07.12 |
도커(docker)에 Qdrant 벡터 데이터베이스 실행하기(로컬 & 클라우드) (0) | 2025.07.12 |
마인드맵으로 아이디어 정리와 실시간 협업 소프트웨어로 업무 성과 창출 (0) | 2024.12.13 |