본문 바로가기

JavaScript/React.js

2. React App

 Vite로 자동 구성한 React App

Vite를 사용하여 React 애플리케이션을 자동으로 구성하는 과정에 대해 설명합니다. Vite는 빠르고 효율적인 개발 환경을 제공하는 도구로, 기본 설정이 적용된 React 앱을 쉽게 생성할 수 있습니다.


🔹 1. Vite

  • 설명: Vite는 현대적인 웹 애플리케이션을 위한 빌드 도구로, 빠른 시작과 핫 모듈 교체(Hot Module Replacement, HMR)를 지원합니다.
  • 명령어: 아래 명령어를 사용하여 Vite를 설치하고 새로운 React 애플리케이션을 생성합니다.
    npm create vite@latest

🔹 2. 프레임워크 선택

  • 설명: 애플리케이션의 프레임워크로 React를 선택합니다.
  • 옵션: 설치 과정에서 react를 선택합니다.

🔹 3. 버전 선택

  • 설명: JavaScript 또는 TypeScript 중 하나를 선택합니다.
  • 옵션: 필요에 따라 TypeScript 또는 JavaScript를 선택합니다.

🔹 4. package.json의 라이브러리 설치

  • 설명: 프로젝트의 종속성을 설치합니다.
  • 명령어: 아래 명령어로 필요한 라이브러리를 설치합니다.
    npm install

🔹 5. public 폴더

  • 설명: public 폴더는 정적 파일을 보관하는 장소입니다.
  • 예시 파일: vite.svg와 같은 정적 파일이 위치합니다.

🔹 6. src 폴더

  • 설명: src 폴더는 동적 파일을 보관하는 장소입니다.
  • 구성 요소:
    • .jsx: JSX 구문을 사용하는 파일로, JavaScript 코드 내에 HTML을 포함할 수 있습니다.
    • assets: 정적 자원을 프로젝트 코드에서 동적으로 사용하는 곳입니다.

 public 폴더와 assets 폴더의 차이

  • public 폴더: 앱 빌드 후 직접적으로 접근할 수 있는 정적 파일들을 저장하는 곳입니다. index.html, favicon, 이미지 등과 같은 파일들이 여기에 포함됩니다. 브라우저에서 직접 접근이 가능합니다.
  • assets 폴더: React 컴포넌트 내에서 사용되는 정적 파일들을 보관하는 곳입니다. 이 파일들은 빌드 후 자동으로 최적화되고, 코드 내에서 동적으로 참조됩니다 (예: 이미지, 폰트, 스타일시트 등).
  • 결론: public은 "브라우저에서 직접 접근" 가능한 파일들을 위한 폴더이고, assets는 React 코드에서 참조하여 사용하는 파일들을 위한 폴더입니다.

🔹 7. .eslintrc.cjs

  • 설명: ESLint 도구의 설정 파일로, 코드 스타일을 통일하고 코드 품질을 향상시키기 위해 사용됩니다.

🔹 8. .gitignore

  • 설명: GitHub에 올릴 때 무시할 파일 목록을 정의합니다. 이 파일에는 node_modules/와 같은 자동 생성 파일들이 포함됩니다.

🔹 9. index.html

  • 설명: 리액트 앱의 기본 틀을 제공하는 HTML 파일입니다. React 애플리케이션이 이 파일을 통해 DOM에 렌더링됩니다.

🔹 10. vite.config.js

  • 설명: Vite의 옵션을 설정하는 파일입니다. 빌드와 개발 서버의 설정을 포함할 수 있습니다.

🔹 11. React App 실행

  • 설명: React 애플리케이션을 실행하기 위한 명령어가 package.json의 scripts 부분에 정의되어 있습니다.
  • 명령어: 아래 명령어로 애플리케이션을 실행합니다.
    npm run dev

 

🔥 결론

Vite를 사용하여 자동으로 구성한 React 애플리케이션은 빠른 개발 환경과 효율적인 구조를 제공합니다. 각 파일과 폴더의 역할을 이해하고, 필요에 따라 커스터마이징함으로써 강력한 웹 애플리케이션을 개발할 수 있습니다! 🚀


 React App 구동 원리

React 애플리케이션의 구동 원리는 기본적으로 npm을 통한 개발 서버 실행과 React의 렌더링 메커니즘을 기반으로 합니다. 이를 통해 동적인 UI를 관리할 수 있습니다.


🔹 1. npm run dev 실행

  • npm run dev 명령어를 통해 Vite 개발 서버를 실행합니다.

🔹 2. 리액트 내장 웹서버 구동

  • 리액트 애플리케이션은 개발 서버를 통해 구동됩니다.
  • 웹 서버는 인터넷 주소와 포트 주소로 구분되며, 일반적으로 localhost:3000 또는 localhost:5173에서 접근할 수 있습니다.

🔹 3. 렌더링 원리

  • React는 index.html 파일의 스크립트 부분을 통해 동적인 UI를 관리합니다.
  • 주요 스크립트 파일은 /src/main.jsx입니다.

🔹 4. main.jsx 파일

  • main.jsx 파일은 React 앱의 진입점으로, ReactDOM의 메서드를 사용하여 컴포넌트를 렌더링합니다.

 내부 메서드

React 앱 구동의 핵심 내부 메서드에는 여러 가지가 있으며, 그 중에서 자주 사용되는 메서드를 설명합니다:

  1. ReactDOM.render()
    • React 컴포넌트를 HTML에 렌더링합니다. index.html에 정의된 특정 div나 다른 DOM 요소에 React 컴포넌트를 삽입합니다.
    • 예시:
      ReactDOM.render(<App />, document.getElementById('root'));
  2. useState()
    • 컴포넌트 내에서 상태를 관리할 때 사용됩니다. 상태가 변경되면 컴포넌트가 재렌더링됩니다.
    • 예시:
      const [count, setCount] = useState(0);
  3. useEffect()
    • 컴포넌트가 렌더링된 후 특정 작업을 실행하는 데 사용됩니다. 주로 API 요청, 구독 등을 처리할 때 사용됩니다.
    • 예시:
      useEffect(() => {
          console.log('컴포넌트가 렌더링되었습니다!');
      }, []);

이 메서드들은 React의 상태 관리, 렌더링, 그리고 라이프사이클 관리에서 중요한 역할을 합니다.

 createRoot()

  • createRoot()는 React 18에서 도입된 메서드로, React 앱을 DOM에 렌더링하는 새로운 방법입니다. React 17까지는 ReactDOM.render()를 사용했지만, createRoot()는 더 효율적이고 향상된 성능을 제공합니다.
  • 이를 통해 앱을 렌더링할 루트를 생성하고, 해당 루트에 컴포넌트를 렌더링합니다.
  • 예시:
     import ReactDOM from 'react-dom/client';
     const root = ReactDOM.createRoot(document.getElementById('root'));
     root.render(<App />);
  • createRoot()는 자동으로 최신 React 기능(예: Concurrent Mode)을 지원합니다.

🔹 5. App.jsx 파일

 App.jsx의 역할

  • UI의 시작점: React 애플리케이션에서 기본적인 UI를 정의하는 컴포넌트입니다.
  • 상태 관리: 애플리케이션의 상태를 useState와 같은 훅을 사용하여 관리합니다.
  • 컴포넌트 렌더링: 다른 컴포넌트를 렌더링하거나 UI를 동적으로 업데이트하는 역할을 합니다.

 실행 순서

  1. React 앱 초기화: Vite로 빌드된 애플리케이션이 실행되면 index.html에서 App.jsx가 호출됩니다.
  2. 상태 설정 및 초기 렌더링: useState로 초기 상태를 설정하고 UI를 렌더링합니다.
  3. 상태 변경 시 리렌더링: 상태가 변경되면 컴포넌트가 다시 렌더링되어 UI가 업데이트됩니다.

 동작 원리

  • 컴포넌트 함수: App.jsx는 함수형 컴포넌트로서 JSX를 반환하고, React가 이를 화면에 그립니다.
  • 상태 변화 감지: useState와 같은 훅을 사용하여 상태 변화에 따라 화면을 자동으로 리렌더링합니다.
  • 이벤트 처리: 버튼 클릭 등 사용자 상호작용에 따라 상태를 변경하고, 이를 화면에 반영합니다.

 특징

  • 함수형 컴포넌트: React에서 권장하는 최신 컴포넌트 작성 방식입니다.
  • JSX: JavaScript 내에서 HTML-like 문법을 사용하여 UI를 정의합니다.
  • 동적 UI: 상태 관리와 이벤트 처리를 통해 UI를 동적으로 변경할 수 있습니다.

 관련 문법

  1. useState: 상태를 관리하는 React 훅.
    const [count, setCount] = useState(0);
  2. JSX 반환: HTML처럼 보이지만 실제로는 JavaScript 코드입니다.
    return <div><h1>Welcome</h1></div>;
  3. 이벤트 처리: React에서는 이벤트 핸들러를 통해 상태를 변경하고 UI를 갱신합니다.
    <button onClick={() => setCount(count + 1)}>Increment</button>

 예제 코드

import React, { useState } from 'react'; // React와 useState 훅을 가져옴

function App() { // App 컴포넌트를 함수형 컴포넌트로 정의
  const [count, setCount] = useState(0); // 상태 변수 `count`와 상태 변경 함수 `setCount`를 선언, 초기값은 0

  return ( // JSX 문법으로 UI 반환
    <div> 
      <p>{count}</p> // 상태 값 `count`를 화면에 출력
      <button onClick={() => setCount(count + 1)}>Increment</button> // 버튼 클릭 시 `count` 값 증가
    </div>
  );
}

export default App; // 다른 파일에서 이 컴포넌트를 사용할 수 있게 내보냄

🔹 6. React 앱 구동 흐름

  1. index.html에서 스크립트 로드:
    • index.html에는 기본적인 HTML 구조와 <div id="root"></div> 요소가 포함되어 있습니다. 이 root div는 React 앱이 렌더링될 대상입니다.
    • <script type="module" src="/src/main.jsx"></script> 태그를 통해 React 앱의 엔트리 포인트인 main.jsx 파일을 로드합니다.
  2. main.jsx 실행:
    • main.jsx 파일에서는 ReactDOM.createRoot()를 사용하여 root div에 React 컴포넌트를 렌더링합니다.
    • createRoot()는 root 요소를 React의 "root"로 지정하고, 해당 요소에 렌더링을 시작합니다.
      import React from 'react';
      import ReactDOM from 'react-dom/client';
      import App from './App';
      
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render();
  3.  
  4. App.jsx 컴포넌트 렌더링:
    • App.jsx 파일에서는 JSX 문법을 사용하여 UI를 정의하고, 이 JSX가 실제 DOM으로 변환되어 렌더링됩니다.
    • React는 App.jsx 컴포넌트를 렌더링하고, 그 결과는 root div에 표시됩니다. React는 상태 관리(useState, useEffect 등)를 통해 동적으로 UI를 업데이트합니다.
  5. 최종 UI 표시:
    • React는 App.jsx에서 반환된 JSX를 가상 DOM에 반영하고, 이를 실제 DOM에 반영합니다. 이 과정에서 UI가 브라우저에 렌더링되고 사용자가 화면을 볼 수 있게 됩니다.

🔥 결론

  • React 앱의 구동 원리는 Vite와 React의 내장 메서드를 통해 이루어집니다.
  • 이 구조를 통해 개발자는 효율적으로 동적인 UI를 구성하고 관리할 수 있습니다. 🚀

 리액트 훅을 사용한 할 일 목록 및 사용자 정보 관리 애플리케이션

이 예제는 React의 여러 훅을 활용하여 상태 관리, 비동기 데이터 처리 및 성능 최적화를 시뮬레이션합니다.


🔹 1. 전체 흐름

  1. MainApp에서 UserContext.Provider가 App 컴포넌트를 감싸며 사용자 정보를 제공합니다.
  2. App 컴포넌트:
    • useState로 카운트를 관리합니다.
    • useReducer로 할 일 목록과 로딩 상태를 관리합니다.
    • useMemo로 계산된 값을 최적화합니다.
    • useCallback으로 handleClick 함수를 메모이제이션합니다.
    • useEffect로 비동기적으로 데이터를 가져와 todos 상태를 업데이트합니다.
    • useContext로 사용자 정보를 전역에서 가져옵니다.

🔹 2. 코드 예시

import React, { useState, useEffect, useMemo, useCallback, useContext, useReducer } from 'react';

// 사용자 정보를 위한 Context 생성
const UserContext = React.createContext();

// useReducer로 상태 관리하는 예시 (할 일 상태 관리)
const initialState = { todos: [], loading: true };

// 리듀서 함수 정의
function reducer(state, action) {
  switch (action.type) {
    case 'SET_TODOS':
      return { ...state, todos: action.payload, loading: false };
    default:
      return state;
  }
}

function App() {
  // 1. useState로 상태 관리 (카운트)
  const [count, setCount] = useState(0);

  // 2. useReducer로 복잡한 상태 관리 (할 일 목록)
  const [state, dispatch] = useReducer(reducer, initialState);

  // 3. useMemo로 계산 비용이 큰 값 메모이제이션
  const expensiveCalculation = useMemo(() => {
    console.log('계산 중...');
    return count * 2;  // 예시로 계산 비용이 큰 작업
  }, [count]);

  // 4. useCallback으로 함수 메모이제이션
  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  // 5. useEffect로 비동기 작업 (API 호출 시뮬레이션)
  useEffect(() => {
    // 2초 후에 할 일 목록을 가져오는 비동기 작업
    setTimeout(() => {
      dispatch({ type: 'SET_TODOS', payload: [{ id: 1, task: 'React 공부' }, { id: 2, task: '앱 만들기' }] });
    }, 2000);
  }, []);

  // 6. useContext로 Context 값 사용 (사용자 정보)
  const user = useContext(UserContext);

  return (
    <div>
      <h1>{user.name}의 할 일 목록</h1>
      <button onClick={handleClick}>Count: {count}</button>
      <p>계산된 값: {expensiveCalculation}</p>

      {state.loading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {state.todos.map(todo => (
            <li key={todo.id}>{todo.task}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

// App 컴포넌트 내에서 Context 제공
export default function MainApp() {
  return (
    <UserContext.Provider value={{ name: '홍길동' }}>
      <App />
    </UserContext.Provider>
  );
}

🔹 3. 주요 동작

  1. 초기 렌더링:
    • count와 todos 상태가 초기화됩니다.
    • useEffect가 실행되어 todos를 비동기적으로 받아옵니다.
    • loading 상태가 true로 설정되어 "Loading..."이 출력됩니다.
  2. 비동기 API 호출:
    • 2초 후, todos 상태를 업데이트하며 loading 상태가 false로 변경됩니다.
  3. 성능 최적화:
    • useMemo는 count가 변경될 때만 재계산합니다.
    • useCallback은 handleClick 함수가 불필요하게 재생성되는 것을 방지합니다.
  4. 전역 상태 관리:
    • UserContext.Provider가 App에 사용자 정보를 제공하고, useContext로 해당 정보를 사용합니다.

🔥 결론

  • 리액트 훅을 사용하여 상태와 부수 효과를 관리하고, 성능을 최적화할 수 있습니다. 각 훅의 사용과 실행 순서를 이해하는 것이 중요합니다.

훅역할특징사용미사용실행 순서

useState 상태 관리 컴포넌트 내에서 로컬 상태를 관리 간단한 상태 관리 (예: 카운터) 상태 로직이 복잡한 경우 1. 초기 상태 값 설정
2. 상태 업데이트 시 리렌더링
useEffect 생명 주기 처리 특정 조건에 따라 부수 효과 실행 API 호출, 타이머 설정 등 의존성 배열을 잘못 설정할 경우 1. 컴포넌트 마운트 후 실행
2. 의존성 변경 시 실행
useMemo 계산 최적화 값의 계산을 메모이제이션하여 성능 최적화 계산 비용이 큰 값의 재계산 필요 자주 변경되는 값에 사용 시 비효율 1. 의존성 배열 변경 시 재계산
2. 메모이제이션된 값 반환
useCallback 함수 메모이제이션 불필요한 함수 재생성 방지 자식 컴포넌트에 콜백 전달 시 의존성이 자주 변경될 경우 1. 의존성 배열 변경 시 함수 재생성
2. 메모이제이션된 함수 반환
useContext 전역 상태 관리 Context API를 통해 상위 컴포넌트의 값 전달 여러 컴포넌트에서 데이터 공유 시 상태가 간단한 경우 1. 최상위 컴포넌트에서 Provider로 값 전달
2. 하위 컴포넌트에서 useContext로 값 사용
useReducer 복잡한 상태 관리 복잡한 상태와 로직을 한 곳에서 관리 여러 액션에 따라 복잡한 상태 변화 상태가 간단한 경우 1. 초기 상태 설정
2. 액션 디스패치로 상태 업데이트

'JavaScript > React.js' 카테고리의 다른 글

1. 리액트 기술적 특징  (0) 2025.01.13
리액트 공부하기  (0) 2025.01.13