자바스크립트 라이브러리인 React.js
를 이용해서 프론트 개발을 해보자
자바스크립트 라이브러리이므로 자바스크립트 환경에서 사용할 수 있다.
먼저 node.js
를 이용해서 자바스크립트 런타임 환경을 만든다.( V8자바스크립트 엔진 )
node.js
는 자바스크립트를 브라우저 밖에서도 사용할 수 있게 해주는데 이로 인해 자바스크립트로 서버를 만들 수 있게 된다.
NPM은 nods.js
의 패키지 관리 시스템이다.
자바스크립트 개발자는 npm을 이용해서 다른 개발자들이 만든 JavaScript패키지를 쉽게 프로젝트에 추가할 수 있다.
스프링부트에서 gradle 의존성을 Maven Repository에서 다운받는것처럼 npmjs( https://www.npmjs.com/ )에서 node.js
라이브러리를 설치한다.
npmjs 에서 node를 다운받아 설치하고 터미널에 npm version으로 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
에는 프로젝트의 메타 데이터가 들어가게 된다.
즉, 디펜던시를 관리할 수 있다.
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
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!
이러한 결과가 나오면 로그가 제안하는데로 커멘드를 실행한다.
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.js
는 index.html
과 함께 가장 처음 실행되는 자바스크립트 코드이다.
이 자바스크립트 코드가 리액트 컴포넌트를 root아래에 추가한다.
const root = ReactDOM.createRoot(document.getElementById('root'));
App.js
는 기본적으로 생성된 리액트 컴포넌트다.
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는 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;
위에서는 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
는 여러 개의 보조 기능이나 유틸리티 함수를 내보내는 데 사용될 수 있다.
두 코드 모두 자바스크립트에서 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는 표현식이기 때문에 자바스크립트 함수가 로직을 통해서 결과를 리턴하기만 하면 된다.