핵심정리

React 기초 정리

아이티프로 2023. 1. 26.
반응형

React는 사용자 인터페이스를 구축하기 위한 자바스크립트 라이브러리이다. 페이스북에 의해 개발되었으며 일반적으로 싱글 페이지 애플리케이션(SPA)을 구축하는 데 사용되며, 개발자들이 웹 페이지의 상태를 효율적이고 효과적으로 구축하고 관리할 수 있게 한다.

○ 재사용을 위한 컴포넌트 기반의 개발: React는 복잡한 UI 요소를 만들기 위해 쉽게 구성할 수 있는 재사용 가능한 컴포넌트기반으로 개발한다.


 Virtual DOM:  컴포넌트의 상태가 변경되면 React는 먼저 가상 DOM을 업데이트한 다음 최소한의 비용으로 실제 DOM을 업데이트한다.


단방향 데이터 흐름: 응답은 데이터가 부모 컴포넌트에서 속성을 통해 자식 컴포넌트로 전달된다. 


 서버사이드 랜더링: 웹 애플리케이션의 성능과 SEO를 향상시킬 수 있다.

 

개발방법 이해

컴포넌트 기반의 개발이므로 페이지를 영역별로 잘 분할하여 컴포넌트를 개발하는 것과 컴포넌트에 값을 전달하고, 컴포넌트간 공유하는 부분과 이벤트전달등이 핵심이 된다. 

 

1. JSX문법으로 컴포넌트 개발 : 재활성을 고려하여 페이지영역을 통 또는 부분분할하여 컴포넌트를 개발한다. 

UI컴포넌트 개발에서  HTML과 유사한 JSX 문법을  사용하며, 개발된 컴포넌트는 export명령어를 통해 외부로 노출된다.

 

2. import 컴포넌트 : 컴포넌트는 import를 통해 삽입이 가능하며 컴포넌트명을 태그형태로 꽂아 넣는다.

 

3. useState를 이용한 상태공유 : 컴포넌트간 상태를 공유하기 위해  useState를 사용해서 상태값이 관리된다.

상태값이 변경되면 해당 컴포넌트는 자동으로 재 랜더링 된다.

 

4. props를 이용한 컴포넌트에 값 전달 : 컴포넌트를 호출할 때 props를 통해 값을 전달할 수 있다.

 

5. Route를 통한 컴포넌트 랜더링 : /page 등의 주소와 컴포넌트를 연결하기 위해서는 Route를 사용한다.

 

개발환경설정

https://itcamp24.tistory.com/209

 

git · node.js · vscode 설치하기

git은 프로젝트의 버전관리를 위해 사용되고 있으며 페키지관리 및 테스트상황에서 node.js를 필수적으로 사용하고 있다. vscode는 MS에서 무료로 배포되는 ide툴로 다양한 extension을 사용하여 프론트

itcamp24.tistory.com

 

HelloWorld! 예제

1. c:\react 폴더를 만들고 이동한 뒤  helloworld 리액트 프로젝트를 생성한다.

cd c:\
mkdir react
cd react
npx create-react-app helloworld

file메뉴 > Open Foler에서 c:\react\helloworld 폴더를 연다. 또는 Open Foler 버튼을 클릭해서 오픈한다.

폴더선택 버튼을 클릭한다.

EXPLORER에서 HELLOWORLD폴더가 보인다.

여기에서 src폴더를 확장시키면 

App.js, index.js 가 보이고

public폴더를 확장시키면

index.html이 보인다.

 

현재까지는 아무런 작업을 하지않아서 create-react-app 이 생성한 디폴트 소스이다.

 

[publc폴더>index.html]

<!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>

이 소스를 살펴보면 index.html에 javascript관련해서 연결 정보가 없다.

 

[src폴더>>index.js]

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

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

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

index.html소스상의 id="root"인  div에 <App />컴포넌트를 render()함수를 사용해서 랜더링해서 꽂아넣도록 되어있다.

 

[src폴더>>App.js]

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

App 컴포넌트 소스로 JSP문법으로 로고와 링크를 추가하는 간단한 샘플이 들어있으며 export default App;로 컴포넌트로 정의되었다.

 

그리고, 이걸 vscode >> 터미널창에서

npm start

를 하면 브라우저 상에서 http://localhost:3000 주소로 아래처럼 보인다.

`npm start`를 하면 node.js에서 컴파일하여 index.html과  index.js를 연결시킨다.

 

그리고 노드를 종료하고 다시 터미널에서

npm run build

를 실행하면 build 폴더아래 관련 리소스를 패키징해서 배포가 된다.

 

여기에서 index.html을 열면

<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/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="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.9bf8d53f.js"></script><link href="/static/css/main.073c9b0a.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

webpack에 의해 빌드되면서 minimized된 html 소스를 보게 된다.  또한 main.9bf8d53f.js 이름으로 minimized된 js소스를 확인할 수 있다.

 

이 과정에서 알 수 있는 것은 index.html은 root라는 랜더링공간을 제공하고 실질적인 메인역할은 index.js가 하고 있음을 알 수 있다. index.js에서 App.js를 임포트해서 <App />라는 컴포넌트를 랜더링하고 있음을 알 수 있다.

 

이제 Hello World를 구현하기 위해 App.js를 다음과 같이 수정한다.

import React, { useState } from 'react';

function App() {
  const [message, setMessage] = useState('Hello World');

  return (
    <div>
      <h1>{message}</h1>
      <button onClick={() => setMessage('Hello from React!')}>
        Update message
      </button>
    </div>
  );
}

export default App;

useState함수를 사용해서 상태정보를 사용한 예제이다.

useState는 실행결과로 첫번째는 변수이고, 두번째는 설정함수를 반환한다.

 

이것을 구조분해 할당(Destructuring assignment) 하면 

 const [message, setMessage] = useState('Hello World');

 

useState('Hello World')의 결과를 받아서

첫번째 인자를 message라는 변수에 초기값으로 'Hello World'라는 문자열을 넣어서 생성하고,

두번째 인자를 받은 setMessage라는 함수를 생성하라는 것이다.

 

구조분해의 결과로 message 라는 변수와 setMessage 라는 함수가 생성이 되었다.

 

 

구조분해 할당은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식이다.

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

 

구조 분해 할당 - JavaScript | MDN

구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.

developer.mozilla.org

 

 

JSX문법에서 {}는 변수나 객체를 연결하는 데 사용하며 

<button onClick={() => setMessage('Hello from React!')}>은 클릭이벤트가 발생하면 

setMessage함수를 실행해서 useState의 값을 'Hello from React!'로 바꾸게 된다.

 

그리고 useState는 <h1>{message}</h1> 가상돔에 연결되어 있으며 값이 변경되면 해당된 영역의

컴포넌트도 재랜더링이 되도록 리액트가 동작한다.

여기서  Update message버튼을 클릭하면

로 자동으로 message가 랜더링 되는 것을 알 수 있다.

 

 

useState()를 사용한 가위 바위 보 게임 예제

cd c:\react
npx create-react-app rockpaperscissors

 

[src >> App.js 를 수정]

import React, { useState } from 'react';

function App() {
  const [computerSelection, setComputerSelection] = useState('바위');
  const [playerSelection, setPlayerSelection] = useState('');
  const [result, setResult] = useState('');

  const selections = ['바위', '보', '가위'];

  function handleClick(playerSelection) {
    setPlayerSelection(playerSelection);
    const randomIndex = Math.floor(Math.random() * selections.length);
    setComputerSelection(selections[randomIndex]);

    if (playerSelection === computerSelection) {
      setResult('Draw!');
    } else if (
      (playerSelection === '바위' && computerSelection === '가위') ||
      (playerSelection === '보' && computerSelection === '바위') ||
      (playerSelection === '가위' && computerSelection === '보')
    ) {
      setResult('You win!');
    } else {
      setResult('You lose!');
    }
  }

  return (
    <div>
      <div>
        <button onClick={() => handleClick('바위')}>바위</button>
        <button onClick={() => handleClick('보')}>보</button>
        <button onClick={() => handleClick('가위')}>가위</button>
      </div>
      <div>
        <p>인간: {playerSelection}</p>
        <p>컴퓨터: {computerSelection}</p>
        <p>{result}</p>
      </div>
    </div>
  );
}

export default App;

컴퓨터의 선택정보와 사용자의 선택정보 그리고 결과정보를 저장하는 useState함수 3개가 정의되어 있다.

 

computerSelection, playerSelection, result 는 각각의 상태를 저장하는 변수이고

setComputerSelection, setPlayerSelection, setResult 는 각각의 상태값을 변경하는 함수이다.

    setPlayerSelection(playerSelection);
    const randomIndex = Math.floor(Math.random() * selections.length);
    setComputerSelection(selections[randomIndex]);

    if (playerSelection === computerSelection) {
      setResult('Draw!');
    } else if (
      (playerSelection === '바위' && computerSelection === '가위') ||
      (playerSelection === '보' && computerSelection === '바위') ||
      (playerSelection === '가위' && computerSelection === '보')
    ) {
      setResult('You win!');

 

'가위', '바위', '보' 버튼을 클릭하면 handleClick 함수가 실행되는 이벤트핸들러를 구현하였다.

<p>인간: {playerSelection}</p>
<p>컴퓨터: {computerSelection}</p>
<p>{result}</p>

에서 인간의 선택과 컴퓨터의 랜덤선택된 것이 보이고 승부여부를 볼 수 있다.

이처럼 useState를 통해 변수값을 UI의 DOM을 연결하고 set함수를 사용하여 값의 변동이 실시간으로 랜더링할 수 있다.

 

props를 사용하여 컴포넌트에 값 전달

React props (properties)는 컴포넌트로부터 부모 컴포넌트로 데이터를 전달하는 기능이다. props는 컴포넌트의 속성값으로 값이 정의되어있으며, 컴포넌트를 호출할 때 전달된 값을 가져온다. 즉, 부모 컴포넌트에서 자식 컴포넌트로 값을 전달할 수 있다. props는 read-only로 값이 정의되어 있으며, 컴포넌트 내에서 변경이 불가능하다.

propsexample 리액트 앱을 생성하고, 해당폴더를 열어서 프로젝트 내용을 수정해 보자.

npx create-react-app propsexample

 

App.js를 수정한다.  data 오브젝트를 생성하여 ChildComponent에 person이라는 이름의 오브젝트형 props를 지정하여 넘긴다.

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

function App() {
  const data = {
    name: 'itpro',
    age: 30,
    occupation: 'Developer'
  };

  return (
    <div>
      <ChildComponent person={data} />
    </div>
  );
}

export default App;

 

ChildComponent.js파일을 만든다. props를 통해 값을 받아서 아래와 같이 전달된 person 오브젝트의 값을 가져와서 뿌려줄 수 있다.

import React from 'react';

const ChildComponent = (props) => {
  return (
    <div>
      <p>Name: {props.person.name}</p>
      <p>Age: {props.person.age}</p>
      <p>Occupation: {props.person.occupation}</p>
    </div>
  );
};

export default ChildComponent;

 

`npm start` 해서 브라우저에서 결과를 보면 props사용하여 자식 컴포넌트로 값이 전달된 것을 확인할 수 있다.

 

 

Route를 사용한  URL패턴으로 화면 전환 SPA구현

URL로 들어온 요청에 대응해 지정된 영역을 랜더링하는 구조로 동작한다.

 

상단에  Home | Blog | About이라는 메뉴를 구성한다.

'http://localhost:3000/'으로 접속하거나 Home을 클릭하면 메인화면이 나오고 

'http://localhost:3000/blog'으로 접속하거나 Blog를 클릭하면 블로그화면이 나오고 

'http://localhost:3000/about'으로 접속하거나 About을 클릭하면  About화면이 나오도록 한다.

 

이를 위해서 react-router-dom을 사용하여 Route를 구성하고, Link를 구성한다.

 

1. react-router-dom이 설치가 안된 경우 다음을 실행

npm install react-router-dom

 

2. routesample 이라는 리액트 프로젝트 생성

npx create-react-app routesample

 

3. Home, Blog, About 컴포넌트 파일 생성

a) Home.js파일을 다음과 같이 생성

import React from 'react';

const Home = (props) => {
	return (
		<div className="content">
			<h3>메인</h3>
			<div>
				메인페이지
			</div>
		</div>
	);
};

export default Home;

 

b) Blog.js 파일 생성

import React from 'react';
import { Link } from 'react-router-dom';

const Blog = (props) => {
    return (
        <div className="content">
            <h3>블로그</h3>
            <ul>
				<Link to="/blog/1"><li>포스팅1</li></Link>
				<Link to="/blog/2"><li>포스팅2</li></Link>
			</ul>
        </div>
    );
}

export default Blog;

 

c) About.js 파일 생성

import React from 'react';

const About = () => {
    return (
        <div className="content">
            <h3>About</h3>
            <div>
                About페이지
            </div>
        </div>
    );
};
  
export default About;

 

4. App.js를 수정하여 라우팅정보를 설정하고 url요청시 해당 컴포넌트를 라우팅해서 랜더링하도록 한다.

import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import Blog from './Blog';
import About from './About';

const App = () => {
	return (
        <div className='App'>
            <BrowserRouter>
                <nav>
                    <ul>
                        <li>
                        <Link to="/">Home</Link>
                        </li>
                        <li>
                        <Link to="/blog">블로그</Link>
                        </li>
                        <li>
                        <Link to="/about">About</Link>
                        </li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/" element={<Home />}></Route>
                    <Route path="/blog/*" element={<Blog />}></Route>
                    <Route path="/about/*" element={<About />}></Route>
                </Routes>
            </BrowserRouter>
        </div>
	);
};

export default App;

a) <BrowserRouter> 컴포넌트 : HTML5의 history API를 활용하여 UI를 업데이트한다. 라우터와 관련된 하위 컴포넌트를 감싸도록 구성한다.

b) <Link> 컴포넌트 : <Link to="/">Home</Link>형태로 사용하여 링크를 생성한다.

c) <Routes> 컴포넌트 : 하위  <Route>를 묶어서 해당 경로의 요청이 들어오면 일치하는 하나와 연결시켜주는 역할을 한다.

d) <Route> 컴포넌트 :  <Route path="/" element={<Home />}></Route>형태로 사용하며 path는 사용자가 요청시 대응하는 url패턴을 기술하고 `*'를 사용하여 특정 경로 하위의 모든 요청에 대응하도록 할 수 잇다. element는 컴포넌트를 지정하여 url로 요청시 해당 컴포넌트를 랜더링 한다.

 

5. index.css에 다음 내용을 추가하여 블로그 메뉴가 상단에 inline-block으로 정렬되도록 하고 마진을 설정하여 안정감을 준다.

.content {
  margin-left: 2rem;
}

nav {
  width: 100%;
}

nav > ul {
  width: 100%;
}

nav > ul > li {
  width: 20%;
  display: inline-block;
}

 

6. npm start로 프로젝트를 실행시켜 결과를 확인

 

 

 

반응형

'핵심정리' 카테고리의 다른 글

HTML 핵심 요약 정리  (0) 2023.02.01
PYTHON 기초 정리  (0) 2023.01.27
jQuery 핵심 정리  (0) 2023.01.25
스프링으로 웹개발 기초  (0) 2023.01.25
SQL 기초 정리 by postgres  (0) 2023.01.25

댓글