실전 리엑트 프로그래밍 1장

1장. 리엑트 프로젝트 시작하기

리엑트.. UI 라이브러리, 혹은 프론트 프레임워크

  • 엥귤러가 웹 어플리케이션 개발에 필요한 다수의 기능을 제공하는 것과 대조적으로, 리엑트는 UI 기능만 제공.
  • 전역 상태 관리, 라우팅, 빌드 시스템 등을 개발자가 직접 구축해야 함
  • 각자의 환경에 맞게 최적화 할 수도 있고, 초심자에게는 높은 진입 장벽
  • 리엑트 팀에서 리엑트의 진입 장벽을 낮추기 위해 create-react-app 만듦.
  • UI를 자동으로 업데이트 해준다는 점이 React를 사용하게 되는 이유겠지
UI = render(state)

변경된 상태값을 기반으로 UI를 자동으로 업데이트

→ React같은 도구를 사용하지 않으면, DOM을 직접 업데이트 해야 하고, 이는 잘 관리하지 않으면 프로그램이 커질수록 복잡도가 기하급수적으로 증가

장점

→ Virtual DOM을 통해 UI를 빠르게 업데이트 함.

Virtual DOM - 가상돔

→ DOM의 데이터가 변경됐을 때 UI에서 변경된 부분을 빨리 찾기 위해 사용되는 범용적인 자료구조.

→ 이전 UI의 상태를 메모리에 유지해서 변경될 UI의 최소 집합을 계산하는 기술

→ 불필요한 UI 업데이트는 줄고, 성능은 좋아짐

React는.

  • Render함수는 순수 함수로 작성해야 한다.

    → 인수 state가 변하지 않으면 항상 같은 값을 반환해야 한다.

  • 컴포넌트 상태값은 불변 객체로 관리해야 한다.

    → 상탯값을 수정할 때에는 기존 객체를 수정하는게 아니라 새로운 객체를 생성해야 함.

    → 순수함수와 불변객체를 사용하면 코드 복잡도가 낮아지고 찾기 힘든 버그 발생 확률이 줄어든다.

    → 그리고 렌더링 성능을 향상시킬 수 있다.

잠시 ReactNative

react-dom 패키지는 웹 어플리케이션에서만 이용되며, 앱에서는 react native. react native는 앱에서 javascript를 실행하기 위해 javascriptCore를 사용. javascriptCore는 webkit에 내장된 javascript engine. react virtual dom은 react native에서도 동작함.

개발환경 생짜로 구축해보기

아래에서 파일을 다운받고. html파일에 createElement를 사용한 js파일을 함께 script참조하여 만들어 볼 수 있음.

https://unpkg.com/react@16.13.1/umd/react.development.js
https://unpkg.com/react@16.13.1/umd/react.production.min.js
https://unpkg.com/react-dom@16.13.1/umd/react-dom.development.js
https://unpkg.com/react-dom@16.13.1/umd/react-dom.production.min.js

html

<html>
<body>
<h2>Desponia's simple react</h2>
<div id="react-root"></div>
<script src="react.development.js"></script>
<script src="react-dom.development.js"></script>
<script src="simple1.js"></script>
</body>
</html>

js

class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {
liked: false
}
}
render() {
const text = this.state.liked ? 'Cancel Liked' : 'Liked';
return React.createElement(
'button',
{onClick: () =>
this.state.liked({ liked: true }),
},
text,
);
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
counts: 0
}
}
render() {
return React.createElement(
'div',
null,
React.createElement(LikeButton),
React.createElement(
'div',
{style: {marginTop: 20}},
React.createElement('span', null, 'Count : '),
React.createElement('span', null, this.state.counts),
React.createElement(
'button',
{ onClick: () => this.setState({ counts: this.state.counts + 1})},
'add',
),
React.createElement(
'button',
{ onClick: () => this.setState({ counts: this.state.counts - 1})},
'minus',
),
)
);
}
}
const domContainer = document.querySelector('#react-root');
ReactDOM.render(React.createElement(Container), domContainer);

Babel

  • 최신 문법을 사용하지 않는 환경을 위해 es5로 변환도 해주고

  • 주석을 제거하거나, 코드를 압축하는 용도로 이용.

  • react애서는 JSX문법을 사용하기 위해 바벨을 사용함.

    → JSX로 작성된 코드를 createElement 함수를 호출하는 코드로 변환해 줌.

    → JSX 문법은 javascript 표준이 아니기 때문에 그대로 실행하면 에러가 발생한다.

npm install @babel/core @babel/cli @babel/preset-react

@babel/cli: command line에서 바벨을 실행할 수 있는 바이너리 파일이 들어 있음.

@babel/preset-react: JSX로 작성된 코드를 createElement함수를 이용한 코드로 변환해주는 플러그인이 들어있음.

  • 패키지로 js파일 변환해보기
npx babel --watch src --out-dir . --presets @babel/preset-react
# src dir에 파일이 있다 치고..
# 같은 폴더 안에 js파일이 변환되어 생성될 것임

npm 명령어는 외부 패키지에 포함된 실행 파일을 실행할 때 사용됨.

외부 패키지의 실행파일은 ./node_modules/.bin/ 아래에 저장됨.

[변환전]

class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {
liked: false
}
}
render() {
const text = this.state.liked ? 'Cancel Liked' : 'Liked';
return React.createElement(
'button',
{onClick: () =>
this.state.liked({ liked: true }),
},
text,
);
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { counts : 0 };
}
render() {
return (
<div>
<LikeButton />
<div style={{ marginTop: 20 }}>
<span>Count~~ : </span>
<span>{this.state.counts}</span>
<button onClick={() => this.setState({ counts: this.state.counts + 1})}>plus</button>
<button onClick={() => this.setState({ counts: this.state.counts - 1})}>minus</button>
</div>
</div>
)
}
}

[변환후]

class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {
liked: false
};
}
render() {
const text = this.state.liked ? 'Cancel Liked' : 'Liked';
return React.createElement('button', {
onClick: () => this.state.liked({
liked: true
})
}, text);
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
counts: 0
};
}
render() {
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(LikeButton, null), /*#__PURE__*/React.createElement("div", {
style: {
marginTop: 20
}
}, /*#__PURE__*/React.createElement("span", null, "Count~~ : "), /*#__PURE__*/React.createElement("span", null, this.state.counts), /*#__PURE__*/React.createElement("button", {
onClick: () => this.setState({
counts: this.state.counts + 1
})
}, "plus"), /*#__PURE__*/React.createElement("button", {
onClick: () => this.setState({
counts: this.state.counts - 1
})
}, "minus")));
}
}

Webpack

Javascript module system C++, java에서 필요한 코드를 이용하도록 import, include 하듯 내보내고 가져다 쓸 수 있도록 구현된 시스템 javascript에서는 es6부터 모듈 시스템이 언어 차원에서 지원되지만 그 이전 버전에서는 commonJS라는 javascript module system을 이용해야 했고, nodeJs가 commonJS 표준을 따르면서 흥하기 시작함. 대부분의 오픈소스도 commonJS로 구현되어 있음.

웹팩은 ESM(es6의 모듈 시스템)과 commonJS 모두를 지원.

이들 모듈 시스템을 이용해서 코드를 작성하고 웹팩을 실행하면 이전 버전의 브라우저에서도 동작하는 자바스크립트 코드를 만들 수 있음.

npm install webpack webpack-cli react react-dom
#이제 모듈 시스템과 npm 덕분에 외부 패키지를 프로젝트에 쉽게 포함할 수 있음

16.8버전 이전의 함수형 컴포넌트는 hook이 없어 상태값과 라이프사이클을 가질 수 없었으나 hook의 도입으로 가능해짐. 페북 내부에도 아직 클래스 컴포넌트가 많아서 앞으로도 쭉 지원할 것 같기는 함.

create-react-app

babel, webpack도 포함되어 있고 테스트 세스팀, HMR(hot-module-replacement), es6+, css후처리 등 거의 필수 개발 환경들을 구축해 줌.

npx create-react-app [원하는프로젝트 이름 in english]
# npm version이 낮은 경우
npm install -g create-react-app
create-react-app [프로젝트이름 in english]
cd [프로젝트 폴더]
npm start

react-programming/create-react-app.png

  • serviceWerker.js 파일에는 PWA(progressive web app)과 관련된 코드가 들어있음.

→ 오프라인에서도 잘 동작하는 웹 어플리케이션을 만들기 위한 기술. 생성시 기본적으로 이 기능이 꺼져있으므로

serviceWorker.register();
  • 개발모드로 실행하면 HMR이 동작하기 때문에 hot reload 가능하다.
  • https로 실행할 수 있는 옵션이 제공되어 있음
# mac
HTTPS=true npm start
# window
set HTTPS=true && npm start
# 위 명령어를 실행하면 자체 서명된 인증서(self-signed certificate)와 함께 https 사이트로 접속 됨
  • build
# 배포환경에서 사용할 파일을 만들어 줌
npm run build
# 로컬에서 웹 서버를 띄워 확인하려면
npx serve -s build

→ build/static/css/main.{해쉬값}.chunk.css

새로 빌드를 해도 변경되지 않은 파일은 동일한 해쉬값을 가지고 있음. 재방문의 경우 캐싱된 파일을 보니 빠르게 페이지 렌더링 할 수 있음.

  • 설정 파일 추출
npm run eject

→ create-react-app의 설정 파일이 노출됨. 웹팩이나 바벨의 설정을 변경할 수 있음. cra의 이후 버전의 변경된 부분을 적용하기 어려운 단점.

  • polyfill 적용

→ cra에는 아무런 polyfill도 적용되지 않음.

npm install core-js
# 이후 index.js 에 한번만 import하면 모든 곳에서 자유롭게 사용할 수 있음
import 'core-js/features/string/pad-start'
// someFile.js
const value = '123'.padStart(5, '0'); // '00123'

→ @babel/polyfill 를 이용해도 폴리필을 추가할 수 있지만 사용하지 않는 기능의 폴리필까지 모두 포함되기 때문에 번들 사이즈가 커지는 단점이 있음.

→ @babel/preset-env는 동적 타입의 언어 한계 때문에 core-js로 직접 추가하는 것 보다 불필요한 폴리필이 포함되는 단점.

  • 환경변수 사용하기
console.log('Node enf = ${process.env.NODE_ENV}')
// NODE_ENV 환경변수 외에는 process.env.REACT_APP_ 로 접근할 수 있음.

SPA (single page application)

최초 요청시 서버에서 첫 페이지를 제공하고 이후의 라우팅은 클라이언트에서 처리하는 웹 어플리케이션.

아래의 두가지 기능이 필요한데,

  • js에서 브라우저로 페이지 전환 request를 보낼 수 있다. 단 브라우저는 서버로 요청을 보내지 않아야 함.
  • 브라우저 뒤로가기 같은 사용자 페이지 전환 요청을 js에서도 처리할 수 있다. 이때도 서버로 요청을 보내지 않아야 함. - history!

위 조건을 만족하는 브라우저 API는 pushState, replaceState 함수와 popState 이벤트

React-router-dom

브라우저 히스토리 API로 페이지 라우팅 처리를 직접 구현해도 되지만

npm install react-router-dom

을 이용해도 내부적으로 브라우저 히스토리 API를 이용해 도움이 됨.

  • BrowserRouter component로 감싸져 있어야 함.
  • 버튼을 통해서 페이지 전환시 Link를 이용
  • Router 컴포넌트로 각 페이지를 정의.

J3
백엔드, 프론트엔드 가리지 않고 모두 관심많은 초절정미녀 개발자입니다~!!