안녕하세요!

FE 개발자 유진주입니다.

Web/React

[Udemy React 완벽 가이드] 섹션 3: 리액트 기초 및 실습 컴포넌트

ypearl 2023. 7. 27. 18:10

컴포넌트란?

스타일을 만드는 HTML + CSS + JS의 결합 단위

[장점]

- 재사용 가능 (Reusability)

=> 재사용가능한 빌딩 블록의 반복을 피하게 한다.

- 우려사항들을 분리 (Separation of Concerns)

=> 코드베이스를 작고 관리 가능한 단위로 유지한다.

 

 

선언적 방식

리액트로 작업할 때는 항상 원하는 최종 상태(목표 상태)를 정의하는 것이 중요하다.

 

리액트가 하는 일은 실제 웹페이지에서 어떤 요소가 추가되거나, 삭제되고, 업데이트 되어야 하는지를 해결하는 것이다. 따라서 자바스크립트에서 하는 것처럼 직접 구체적인 DOM을 업데이트하는 지침들을 작성할 필요가 없다.

 

Node.JS 설치 및 리액트 프로젝트 생성

리액트 설치 오류 시

[해결 방법]

1. 전역 설치된 리액트 앱 삭제

npm uninstall -g create-react-app	// 설치 앱 삭제

2. npm으로 리액트 다시 설치

npm add create-react-app

3. 해당 작업 폴더에서 npx로 다시 설치

npx create-react-app (폴더명)	// React설치

npm start	// 잘 설치된 React 확인 후

 

표준 리액트 프로젝트 분석

index.js

: localhost:3000이 로드되면 가장 먼저 실행되는 파일

(개발자 서버 가동 방법 : Terminal 창> npm start )

* npm start 프로세스는 코드를 살펴보고 실행하며 브라우저에 전달하는 것뿐만 아니라

전달하기 전에 코드를 변형해서 추가 기능이 브라우저에서 작동하도록 해준다.

import ReactDOM from 'react-dom/client';

import './index.css';	// CSS 파일을 JavaScript 파일로 가져옴 (원래는 잘못된 구문)
import App from './App';	// ./의 의미: index.js 파일과 동일한 폴더에 있음.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);	// JavaScript 파일 내의 HTML 코드 (원래는 잘못된 구문)

[알아두기😉]
- createRoot 메서드
: React를 사용하여 구축할 전체 사용자 인터페이스의
  메인 엔트리 포인트 혹은 메인 훅을 생성
  (만들 사용자 인터페이스가 로딩되는 웹 페이지의 어느 곳에 위치해야 하는지 알려준다.)

 

[참고]

- npm start 프로세스를 통해

애플리케이션 전반에 index.css 파일을 추가해달라고 요청.

(해당 CSS 코드를 인식해 화면의 페이지에 주입하라고 명령하는 것)

그러면 그 안에 정의된 font-family, background-color 등의 스타일이

화면 속 페이지에 적용되어 나타난다.

 

✨ 꼭 기억해야 할 2가지!

- 편하고 쉽게 작성한 코드도 모든 브라우저에서 실행될 수 있다.

- index.js 파일이 가장 먼저 실행되는 파일이다.

 

index.html

: 단일 HTML 파일로서 브라우저에서 로딩

*오직 이 HTML 파일만이 React 애플리케이션에서 사용됨(=싱글 페이지 애플리케이션(SPA))

(그 외 웹 페이지 상의 모든 사용자 인터페이스 관련 변경 사항은 React가 처리)

 

- 엔트리 포인트로서 React가 관리하는 사용자 인터페이스 전반이 렌더링 될 위치

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

 

- 일반적인 div 태그지만 아무런 콘텐츠도 없다?

: div 태그 안에 React가 관리하는 사용자 인터페이스가 렌더링된다.

// index.js

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

// index.html

<div id="root"></div>

[➕설명 덧붙이기]
이렇게 일반 JavaScript 코드로 root를 선택하여
해당 root에 React(ReactDOM) 라이브러리 메서드를 사용.

해당 메서드는 React에게 이것이 React 애플리케이션의 루트(root)이자
React 애플리케이션이 렌더링될 주된 위치라는 점을 알려준다.
=> createRoot 메서드의 역할

이제 이 root 객체를 상수 또는 변수에 저장한 뒤
root 객체에서 render 메서드를 호출하여
React에게 선택된 div에서 무엇이 렌더링되어야 하는지를 알려준다.

✨ span이나 p 요소를 선택할 수도 있지만,
   div가 가장 일반적인 root 요소이다.

 

App이란?

: App.js 파일에서 가져온 App

[참고] import로 가져올 때는 항상 확장자(.js)가 없어야 한다.

(CSS 파일과 같은 경우엔 추가해야 하지만, 서드파티 라이브러리나 js 파일 중 하나라면 .js를 빼야 한다)

 

App은 말하자면 컴포넌트이다!

// index.js
import ReactDOM from 'react-dom/client';

import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

[알아두기😉]
이 App 컴포넌트는 root라는 id를 갖는
요소가 있는 곳에 렌더링되는 컴포넌트이다.
즉 div 태그, 정확히는 이 div 태그 내에 렌더링되는 것!
 

 

App.js

: 한 파일에 정의된 함수, 클래스 또는 객체를 다른 파일에서 사용하고자 하는 경우

내보내고 가져오는 과정이 필요한데, 이때 해당 함수가 정의되어 있는 파일.

* App.js에서 내보낸 다음, index.js 파일에 가져오는 것!

(App.js 파일에 정의된 함수를 index.js 파일에서 쓸 수 있음)

 

function App() {
  return (
    <div>
      <h2>Let's get started!</h2>
    </div>
  );
}

export default App;

[알아두기😉]
일반적으로 볼 수 있는 유효한 JavaScript 코드가 아님.
그런데도 문제 없이 작동할 수 있는 이유는
JSX라는 기능 덕분.

 

JSX

: 자바스크립트 XML(HTML)

= 자바스크립트 안에 HTML 코드를 가지는 형태

✨ 화면 뒷단에서 실행되는 변환 과정이 존재한다.

 

크롬 > 도구 더보기 > 개발자 도구 > Source 탭 (모든 소스와 스크립트 확인 가능)

Ctrl + F : 파일의 어느 부분에 함수가 있는지 검색 가능.

* VS Code에서 작성한 코드가 아닌, 브라우저에서 실행되는 변환된 코드를 확인할 수 있다!

[ 규칙🔥 ] 반환하는 문장마다 또는 JSX 코드 조각마다 반드시 한 개의 루트 요소를 가져야 한다.

 

리액트 작동 방식

페이지에서 어떤 요소를 선택하려면?

❌ 명령적 접근 방식
document.getElementByID('root').innerHTML='';
또는
document.createElement('p');
또는
const para = document.createElement('p');
para.textContent = 'This is also visible';
document.getElementById('root').append(para);

⭕ 선언적 접근 방식 - React 식
<div>
    <h2>Let's get started!</h2>
    <p>This is also visible!</p>
</div>

 

리액트 작업 컴포넌트 트리

리액트 작업 컴포넌트 트리

- 맨 위에 가장 중요한 App 컴포넌트

- 그 아래에는, 어떤 종류의 사용자 지정 html 요소라도 가질 수 있음.

(결국 사용자 인터페이스를 만드는 조각들을 갖는 컴포넌트)

- 맨 위에 있는 컴포넌트만이 리액트 돔 렌더의 지시로 html 페이지에 직접 렌더링 된다.

- 그 외의 모든 다른 컴포넌트들은 html 코드 안에 있는 보통의 html 요소들을 사용해서 렌더링 된다.

 

➕ 파일 이름 정할 때,

- 대문자로 시작하는 한 단어

(여러 단어 결합 시 중간에 시작하는 서브 단어는 대문자로 시작)

- 파일 이름을 보면 어떤 로직과 HTML 파일이 안에 있을지 파악 가능하도록!

 

 

사용자 지정 컴포넌트 만들기 (★)

: 항상 아래와 같은 순서로 진행하면 된다.

(Html코드를 리턴하는 함수인 컴포넌트를 생성해서 내보내는 방식)

 

- ExpenseItem.js

: 이곳에서 반환하는 html 코드는 JSX 코드 컴포넌트로 화면에 불러와져야 함.

 

// ExpenseItem.js
function ExpenseItem() {	// 관습상 파일 이름은 반복 사용
    return <h2>Expense item!</h2>	// 기본적인 사용자 지정 컴포넌트
}

export default ExpenseItem;	// 컴포넌트를 사용하기 위해 이 함수를 이 파일의 기본함수로 내보내기(export)

- App.js

// App.js
import ExpenseItem from './components/ExpenseItem';
// index.js 파일에 임포트 하는 것이 아닌,
// 루트 컴포넌트를 위해 App.js 파일의 맨 위에 사용자 지정 컴포넌트를 불러옴(import)

function App() {
  return (
    <div>
      <h2>Let's get started!</h2>
      <p>This is also visible!</p>
      <ExpenseItem></ExpenseItem>
      // 파일이 import 되었기에, 이제 이 함수를 html 요소처럼 사용할 수 있다.
    </div>
  );
}

export default App;

🚨 주의점
사용자 지정 컴포넌트는 내장된 html 요소(소문자 시작)와는 달리,
반드시 대문자로 시작한다!
=> 이것으로 리액트는 사용자 지정 컴포넌트를 감지함.
* import한 이름을 사용할 것
function ExpenseItem() {
  return (
    <div>
      <div>March 28th 2021</div>
      <div>
        <h2>Car Insurance</h2>
        <div>$294.67</div>
      </div>
    </div>
  );
}

export default ExpenseItem;

 

기본 CSS 스타일 추가

// ExpenseItem.js
import './ExpenseItem.css';	// ExpenseItem.css를 import

function ExpenseItem() {
  return (
    <div className="expense-item">	// ⚠ 일반적으로 html에서 사용하던 class가 아닌 className을 사용.
      <div>March 28th 2021</div>
      <div className="expense-item__description">
        <h2>Car Insurance</h2>
        <div className="expense-item__price">$294.67</div>
      </div>
    </div>
  );
}

export default ExpenseItem;

 

적용 화면 ( .css 파일은 강의 제공 파일)

 

JSX에서 동적 데이터 출력 및 표현식 작업

import './ExpenseItem.css';

function ExpenseItem() {
  const expenseDate = new Date(2021, 2, 28);
  const expenseTitle = 'Car Insurance';
  const expenseAmount = 294.67;

  return (
    <div className="expense-item">
      <div>{expenseDate.toISOString()}</div>	// JSX코드 안의 중괄호{} = 안에서 기본적인 자바스크립트 코드 실행 가능
      <div className="expense-item__description">
        <h2>{expenseTitle}</h2>
        <div className="expense-item__price">{expenseAmount}</div>
      </div>
    </div>
  );
}

export default ExpenseItem;

 

"props"를 통해 데이터 전달