본문 바로가기

JavaScript/React.js

2. React App

728x90
반응형

 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. 액션 디스패치로 상태 업데이트
728x90
반응형

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

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