[React] 무작정 해보기

merci·2023년 5월 24일
0

자바스크립트 라이브러리인 React.js를 이용해서 프론트 개발을 해보자

자바스크립트 라이브러리이므로 자바스크립트 환경에서 사용할 수 있다.
먼저 node.js를 이용해서 자바스크립트 런타임 환경을 만든다.( V8자바스크립트 엔진 )

node.js는 자바스크립트를 브라우저 밖에서도 사용할 수 있게 해주는데 이로 인해 자바스크립트로 서버를 만들 수 있게 된다.

NPM ( Node Package Manager )

NPM은 nods.js의 패키지 관리 시스템이다.
자바스크립트 개발자는 npm을 이용해서 다른 개발자들이 만든 JavaScript패키지를 쉽게 프로젝트에 추가할 수 있다.
스프링부트에서 gradle 의존성을 Maven Repository에서 다운받는것처럼 npmjs( https://www.npmjs.com/ )에서 node.js라이브러리를 설치한다.

npmjs 에서 node를 다운받아 설치하고 터미널에 npm version으로 npm설치를 확인한다.

npm 프로젝트 초기화

npm 프로젝트를 초기화 하려는 디렉토리로 이동후 터미널에 다음을 입력한다.

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (test-project) # 여기부터 엔터
version: (1.0.0)
description: test-project
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC) # 여기까지 엔터치면 아래 package.json을 만들어준다.
About to write to C:\workspace\javascript_lab\test-project\package.json:

{
  "name": "test-project",
  "version": "1.0.0",
  "description": "test-project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes) # 엔터

package.json

package.json에는 프로젝트의 메타 데이터가 들어가게 된다.
즉, 디펜던시를 관리할 수 있다.

test-project 디렉토리에는 아래와 같은것들이 초기화 된다.
여기에서 아래 코드로 react를 설치하면 ( npm install 'package-name' )

npm install react

node_modules 디렉토리에 설치가 된다.

test-project 디렉토리의 package.json에도 리액트 디펜던시가 추가된다.

{
  "name": "test-project",
  "version": "1.0.0",
  "description": "test-project",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^18.2.0"
  }
}

또한 node.js 의 경우 의존성을 추가하려면 커멘드를 이용해 의존성이 있는 라이브러리를 추가할 수 있다.
깃 리포지토리에서 코드를 받았다면 아래코드로 모든 패키지를 설치할 수 잇다.

npm install


React 설치

https://velog.io/@merci/React-%EC%84%B8%ED%8C%85 를 참고해서

디렉토리를 하나 만들고 커멘드를 입력한다.
npx 를 이용하면 번거로운 설정을 자동으로 해준다.

$ npx create-react-app my-app
npm WARN exec The following package was not found and will be installed: create-react-app@5.0.1
npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.

Creating a new React app in C:\workspace\javascript_lab\react-workspace\my-app.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...

# 중간 생략..

We suggest that you begin by typing:

  cd my-app
  npm start

Happy hacking!

이러한 결과가 나오면 로그가 제안하는데로 커멘드를 실행한다.

포트 3000 사용중

  cd my-app
  
  $ npm start

> my-app@0.1.0 start
> react-scripts start

? Something is already running on port 3000.

Would you like to run the app on another port instead? » (Y/n)

검색해보니 사용중인 포트를 알 수 있는 명령어가 있던데 아래 명령어로 3000포트를 찾을 수 없었다.

netstat -ano
# 혹은 3000포트를 지정해서 검색
netstat -ano | findstr 3000

조회가 되면 아래 명령어로 삭제한다.

kill -9 PID

윈도우에서는 아래 명령어를 사용한다.

taskkill /f /pid {pid 번호}

조회가 안되면 3000포트를 삭제한다.

$ npx kill-port 3000
npm WARN exec The following package was not found and will be installed: kill-port@2.0.1
Process on port 3000 killed

다시 npm start를 하면

npm start
# .....
Compiled successfully!

You can now view my-app in the browser.

  Local:            http://localhost:3000        
  On Your Network:  http://[내 아이피]:3000  

Note that the development build is not optimized.
To create a production build, use npm run build. 

webpack compiled successfully

다시 조회를 하면

netstat -ano | findstr 3000
  TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       7388
  TCP    127.0.0.1:3000         127.0.0.1:5876         ESTABLISHED     7388
  TCP    127.0.0.1:5876         127.0.0.1:3000         ESTABLISHED     13676

3000 포트로 실행되면 리액트 페이지로 열린다.


프로젝트 구성


public 디렉토리 하위에 index.html파일이 있다.

http://localhost:3000 이 처음 리턴해주는 index.html을 브라우저가 렌더링한다.
리액트에서 html은 이거 단 하나 이고 다른 페이지들은 React.js를 통해 생성된다.

src 디렉토리는 다음처럼 구성되어 있다.

index.jsindex.html과 함께 가장 처음 실행되는 자바스크립트 코드이다.
이 자바스크립트 코드가 리액트 컴포넌트를 root아래에 추가한다.

const root = ReactDOM.createRoot(document.getElementById('root'));

App.js는 기본적으로 생성된 리액트 컴포넌트다.

material-ui

UI패키지를 이용하면 UI를 위한 컴포넌트나 css를 작성하지 않아도 된다.

npm install @material-ui/core

설치하려니까 버전이 맞지 않음 ERR 가 발생
npx로 리액트를 설치하면 항상 최신버전을 설치해서 발생한 문제다.
리액트 17 버전이 필요해서 다운그레이드를 진행한다.
우선 루트 디렉토리의 package.json의 디펜던시를 수정한다.

  "dependencies": {
    "@testing-library/react": "^12.0.0",
    "@testing-library/user-event": "^12.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
  },

실행중인 포트를 종료하고 리액트를 다시 설치하고 실행시킨다.

kill -9 PID
npm install
npm start

이후 실행화면은 아래와 같은 문제가 발생한다.

17버전과 18버전은 DOM렌더링 방식이 다르다.

src패키지의 index.js를 수정해야한다.
https://curryyou.tistory.com/468 를 참고했다.

// import ReactDOM from 'react-dom/client'; // react v18 버전용
import ReactDOM from 'react-dom';  // react v17 버전용
// react v 18 버전 용
// const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
// root.render(
//   <React.StrictMode>
//         <App />
//   </React.StrictMode>
// );

// react v 17 버전용
ReactDOM.render(
  <React.StrictMode>
        <App />
  </React.StrictMode>,
  document.getElementById('root')
);

수정하면 다시 정상적인 리액트 초기화면이 브라우저에 나온다.
다시 material-ui를 설치한다.

npm install @material-ui/core
npm install @material-ui/icons


SPA

SPA는 Single Page Application의 약자로 기본적으로 한개의 웹페이지로 이루어진 애플리케이션을 말한다.
HTML은 모든 페이지 요청마다 HTML을 리턴해주는데 SPA는 초기 페이지를 로딩한 후 모든 뷰의 업데이트를 자바스크립트를 통해 동적으로 처리한다.
SPA에는 React.js / Angular.js / Vue.js 등이 있다.
SPA에는 SEO( 검색 엔진 최적화 )의 문제가 있다.

처음 로딩된 index.html 은 아무것도 없는 페이지인데 자바스크립트인 리액트가 DOM을 제어해서 화면을 바꾸게된다.

ReactDOM.render(
  <React.StrictMode>
        <App />  // 리액트 컴포넌트	
  </React.StrictMode>,
  document.getElementById('root')
);

이런식으로 페이지를 변경하는 요청을하면 자바스크립트 함수가 데이터를 서버로부터 받은 뒤 동적으로 html을 재구성하는데 이 과정이 브라우저에서 이루어지므로 CSR이라고 한다.

리액트 컴포넌트

리액트 애플리케이션을 생성하면서 만들어진 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;

하단의 export default App;를 통해서 다른 컴포넌트에서도 App컴포넌트를 사용할 수 있다.

또는 자바스크립트 클래스로도 똑같은 기능을 하는 App컴포넌트를 만들 수 있다.

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

class App extends React.Component {
  render() {
    return (
      <div className="App">
      	... // JSX code
      </div>
    );
  }
}

export default App;

Named export / Default export 차이

위에서는 export default App; 코드로 Default export로 컴포넌트를 만들고 있다.
리액트에서 컴포넌트를 만들기 위해서는 export가 필요한데 두가지 방법이 있다.

// Named export
export const myComponent = () => {
  // 컴포넌트 로직
};

// 컴포넌트 사용시
import { myComponent } from './myComponent';
// Default export
const myComponent = () => {
  // 컴포넌트 로직
};

export default myComponent;

// 컴포넌트 사용시
import MyComponent from './myComponent';

Default export는 파일당 하나만 만들 수 있으며 호출시에 중괄호가 필요하지 않다.
반면에 Named export는 파일에 여러개를 만들 수 있고 호출시에는 중괄호를 사용해야 한다.

일반적으로 default export는 해당 모듈이 기본적으로 제공하는 기능이나 컴포넌트를 가리킬 때 사용한다.
Named export는 여러 개의 보조 기능이나 유틸리티 함수를 내보내는 데 사용될 수 있다.


JSX, Babel

두 코드 모두 자바스크립트에서 html을 사용하는데 React가 파일안에서 html과 자바스크립트를 함께 사용하기 위해 확장한 스크립트 문법이기 때문이다.
이러한 문법을 JSX ( JavaScript XML )라고 부른다.

이렇게 리턴된 리액트 컴포넌트를 보통 Babel라이브러리를 이용해 자바스크립트로 변환해준다.
위에서 npx create-react-app 명령어로 설정을 자동으로 했는데 이 설정 안에 Babel도 설정되어 있다.
브라우저는 JSX를 변환할 필요 없이 Babel이 JSX를 자바스크립트로 변환해준다.

ReactDOM.render(
  <React.StrictMode>
        <App />  // 리액트 컴포넌트 ( JSX ) -> 자바스크립트로 변환
  </React.StrictMode>,
  document.getElementById('root')
);

아래와 같은 JSX코드를 리턴했다면

let jsx = (
<div className="App">
  </div>
  );

Babel 라이브러리가 아래처럼 자바스크립트로 변환해준다.

  "use strict";
  
  let jsx = 
    React.createElement(
      "div", { className: "App" }
    );

이를 통해 ReactDOM.render() 함수의 매개변수로 <App />을 주면 리액트가 Dom 트리를 만들고 렌더링을 하게 된다.

JSX를 좀더 알아보면

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

JSX의 중괄호 안에는 유효한 모든 자바스크립트 표현식을 넣을 수 있다.
아래의 코드처럼 표현식의 결과를 <h1>태그의 엘리먼트로 포함시킨다.

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

JSX는 표현식이기 때문에 자바스크립트 함수가 로직을 통해서 결과를 리턴하기만 하면 된다.

profile
작은것부터

0개의 댓글