티스토리 뷰
왜 리액트인가?
자바스크립트 기반 여러 프레임워크(Vue.js, ANGULAR.js)등은
MVC(Model-View-Controller)아키텍처, MVVM(Model-View-View Model)아키텍처,
앵귤러JS는 MVW(Model-View-Whatever) 아키텍처로 APP을 구조화한다.
위 아키텍처들의 공통점
모델과 뷰가 있다.
모델 : APP에서 사용하는 데이터를 관리하는 영역
뷰 : 유저에게 보여주는 부분
동작 : 프로그램이 유저에게 데이터를 받으면 데이터를 조회/수정하고, 변경 사항을 뷰에 반영한다.
예시)
다음 JSON 객체 값을 사용하는 뷰가 있다.
{
"title" : "Hello",
"contents": "Hello World"
}
<div id="post-1">
<div class="title">Hello</div>
<div class="contents">Hello World</div>
</div>
contents의 값을 업데이트 한다면 APP에서 post-1을 찾아 contents요소를 수정해야 한다.
APP의 규모가 커지면 이 작업이 복잡해지고, 제대로 관리를 해주지 않는다면 성능도 떨어질 수 있음
페이스북 개발 팀에서는 이것을 해결하려고 데이터가 변할 때, 해당 데이터를 변화시키는 것이 아닌
기존 뷰를 날려 처음부터 새로 렌더링 하는 방식을 고안해냈다.
이러면 APP의 구조가 매우 간단하고, 코드양도 줄게된다.
이 방식으로 구현하기 위해 개발한 것이 바로 리액트이다.
리액트 이해하기
리액트는 JS 라이브러리로 UI를 만드는데 사용. 오직 View만 신경 쓰는 라이브러리이다.
리액트에서 특정 부분이 어떻게 생길지 정하는 선언체가 있음.
이것을 컴포넌트라 부른다. 재사용이 가능한 API로 수많은 기능을 내장.
하나의 컴포넌트에서 해당 컴포넌트의 생김새와 작동 방식을 정의한다.
사용자에게 뷰를 보여주는 것을 렌더링이라고 한다.
리액트에서 매번 새롭게 렌더링을 하지만, 좋은 성능을 유지하고, 최적의 유저 경험을 제공할 수 있는 이유를 알고 싶다면 리액트 컴포넌트가 최초로 실행한 '초기 렌더링'과 컴포넌트의 데이터 변경으로 다시 실행되는 '리렌더링'개념을 이해해야 한다.
초기 렌더링
UI 관련 프레임워크, 라이브러리를 사용할 때 가장 처음 어떻게 보일지를 정하는 초기 렌더링이 필요
리액트에선 이를 다루는 render 함수가 있음
render() {...}
함수의 역할
컴포넌트가 어떻게 생겼는지 정의하는 역할.
html 형식의 문자열을 반환하지 않고, 뷰의 생김새, 동작방식의 정보를 지닌 객체를 반환
컴포넌트 내부에선 또 다른 컴포넌트들이 들어갈 수 있다.
함수의 실행
내부 컴포넌트들을 재귀적으로 렌더링.
최상위 컴포넌트의 렌더링 작업이 완료되면 지니고 있는 정보를 통해 HTML 마크업을 만들고
실제 페이지의 DOM 요소에 주입
컴포넌트를 실제 페이지에 렌더링할 땐 분리된 두 가지 절차를 따르며 이벤트를 적용
1. 문자열 형태의 HTML 코드를 생성
2. 특정 DOM에 해당 내용 주입
조화 과정
뷰를 업데이트 하는 과정
업데이트를 업데이트 과정을 거친다고 하기보단 '조화 과정(reconciliation)을 거친다"라고 표현.
이유 : 컴포넌트에서 데이터가 변화 되었을 때 뷰를 변형하는 것이 아닌 새로운 요소로 갈아 끼우기 때문
조화 과정 또한 render 함수가 맡아서 한다.
render는 뷰의 생김새와, 작동 방식을 객체로 반환한다.
컴포넌트는 데이터를 단순히 업데이트하는 것이아닌 새로운 데이터를 가지고 render 함수를 재호출.
그럼 변경된 데이터를 가진 뷰가 생성이 된다.
이렇게 생성한 뷰를 바로 DOM에 반영하지 않고,이전에 render가 만들었던 컴포넌트 정보와 현재 컴포넌트 정보를 비교.
자바 스크립트를 사용해 두 개의 뷰를 최소한의 연산으로 비교. 그리고 차이가 발생하는 부분을 최소한의 연산으로 DOM트리를 업데이트한다.
리액트 특징
DOM(Document Object Model)
객체로 문서 구조를 표현하는 방법.
XML이나 HTML로 작성
웹 브라우저는 DOM을 활용해 객체에 JS와 CSS를 적용.
트리형태라 특정 node를 찾아 수정/제거, 원하는 곳에 삽입 가능
치명적 문제
동적 UI에 최적화되어 있지 않음.
HTML 자체가 정적. 이것을 JS를 사용해 동적으로 만드는 것.
DOM이 느리다는 말은 틀린 것.
DOM 자체를 읽고 쓰는 것은 JS 객체 처리와 비교했을 때 다를바 없음.
단, 웹 브라우저에서 DOM에 변화가 발생했을 때
CSS를 재연산하고, 레이아웃을 구성하고, 페이지를 리페인트하는 과정이 느린 것
해결법
DOM을 최소한으로 조작해 작업을 처리하는 방식으로 개선
리액트에선 Virtual DOM 방식을 사용해 DOM 업데이트를 추상화함으로써
DOM 처리 횟수를 최소화하고 효율적으로 진행
Virtual DOM
실제 DOM 대신, 이것을 추상화한 JS 객체를 구성해 사용. 실제 DOM의 사본과 비슷.
리액트에서 데이터가 변했을 때 웹 브라우저에 실제 DOM을 업데이트 하는 절차
1. 전체 UI를 Virutal DOM에 리렌더링
2. 이전 Virtual DOM의 내용과 현재 내용 비교
3. 바뀐 부분만 실제 DOM에 적용
Virtual DOM을 사용한다고 무조건 빠르지 않음
리액트와 Virtual DOM이 항상 제공할 수 있는 건 업데이트 처리의 간결성임.
UI를 업데이트 하는 과정에서 생기는 복잡함을 해소하며, 더욱 쉽게 업데이트에 접근 가능
리액트 프로젝트 생성하기
npm이나 yarn을 설치하는 부분은 다루지 않음
1. create-react-app
텅 빈 프로젝트부터 시작하여 도구들을 설치하고 하나하나 설정하는 것이 정석.
위 도구는 프로젝트의 핵심 기능들의 설정을 미리 완료한채 프로젝트 생성 가능
2. 설치하기
1번의 도구는 yarn이나 npm으로 설치 가능.
패키지의 설치 방법 : 지역, 전역
둘의 차이는 프로젝트 디렉터리에서만 사용할지, 모든 디렉터리에서 사용할지이다.
3. 프로젝트 생성하기
npx create-react-app begin-react
터미널에서 위 명령어를 실행하면 생성이 된다.
4. 서버 실행하기
yarn start 명령어로 프로젝트 개발 서버를 실행할 수 있음.
3000번 포트로 열리며 파일을 수정할 때마다 프로젝트 재빌드 후 웹 브라우저를 리로딩한다.
코드 분석하기
// 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;
// src/index.js
import React from 'react';
import React from 'react';
import 키워드를 사용해 모듈을 불러오는 것이다.
이렇게 파일을 모듈화해서 사용하는 것은 Node.js의 기능.
웹 브라우저에서 사용하는 js는 Node.js 런타임으로 실행하는 것이 아니라 자체적으로 이 기능을 지원하지 않음
웹 브라우저에서 이렇게 해야할 때는 html 파일 안에 script 태그를 사용해 여러 파일을 불러온다.
하지만 이런 특징을 웹 브라우저에서 비슷하게 사용할 수 있는 방법이 있다.
bundling 도구를 이용하는 것. bundle은 묶는다는 의미. 즉 파일을 묶듯이 연결하는 것이다.
bundling 도구 : Browserify, RequireJS, webpack이 대표적.
리액트에선 webpack을 주로 사용. 이유 : 편의성과 확장성이 다른 도구보다 뛰어남.
이런 도구를 사용해 import로 모듈을 불러오면 번들링되면서 모듈들을 파일 하나로 합쳐준다.
import logo from './logo.svg';
import './App.css';
SVG와 CSS 파일도 webpack으로 불러올 수 있음. 이 기능은 webpack의 loader가 담당한다.
로더의 종류는 여러 가지가 있다.
css-loader : CSS 파일 로드
file-loader : 웹 폰트, 미디어 파일 로드
babel-loader : js 파일 로드(ES6 코드를 ES5문법으로 변환)
ES5로 변환하는 이유
구 버전 웹 브라우저와 호환을 위함.
ES6의 class 문법
class Dog {
constructor(name) {
this.name = name;
}
say() {
console.log(this.name + ': 멍멍');
}
}
const dog = new Dog('흰둥이');
dog.say(); // 흰둥이: 멍멍
function App()
App이라는 함수를 만든 것이다. App.css 파일에서 각 className을 어떻게 표현할지 작성한다.
그리고 index.js에서 ReactDOM.render 함수에서 <App /> 이라는 형태로 작성을 해주면
웹 브라우저에 표현이 된다.
App 내부에 작성된 코드는 JSX라고 한다.
ReactDOM.render란?
컴포넌트를 페이지에 렌더링하는 역할, react-dom 모듈을 불러와 사용.
첫 파라미터에는 페이지에 렌더링할 내용을 JSX 형태로 작성,
두 번째 파라미터에는 JSX를 렌더링할 document 내부 요소 설정
root가 작성되어 있을 텐데 해당 요소는 public/index.html 파일에 존재
JSX란?
JS의 확장 문법으로 XML과 비슷하게 생김.
JSX로 작성한 코드는 나중에 코드가 번들링되면서 babel-loader를 사용해 JS로 변환.
JSX의 코드 변환 과정
var a = (
<div>
<h1>Awesome <b>React</b></h1>
</div>
)
이 코드를 바벨로 변환하면 다음 형식이 된다.
var a = React.createElement(
"div",
null,
React.createElement(
"h1",
null,
"Awesome ",
React.createElement(
"b",
null,
"React"
)
)
);
이렇게 변환하면서 컴포넌트를 트리 구조의 객체로 정의가 가능
JSX의 장점
1. 보기 쉽고 익숙하다.
HTML 코드를 작성하는 것과 비슷해서 보기 쉽고 편함.
2. 오류 검사
JSX에 오류가 있다면, 바벨이 코드를 변환하는 과정에서 감지한다. (ex : 태그를 닫지 않았을 때)
3. 높은 활용도
div, span 같은 HTML 태그를 사용할 수 있고, 컴포넌트도 작성 가능.
JSX 문법 규칙
1. 태그는 꼭 닫아야 한다.
열려 있으면 오류가 발생하게 된다.
import React from 'react';
import Hello from './Hello';
function App() {
return (
<div>
<Hello />
<Hello />
<Hello />
<div>
</div>
);
}
export default App;
//
Failed to compile
Parsing error : Unterminated JSX contents
<Hello />
<div>
부분에 태그가 열려 있기 때문에 오류를 발생한다.
태그와 태그 사이에 내용이 들어가지 않는다면 Self Closing 태그를 사용해야 한다.
열리고 바로 닫히는 태그를 의미한다.
<br />
<Hello />
2. 꼭 감싸져야 하는 태그
두 개 이상의 태그는 무조건 하나의 태그로 감싸져야 한다.
이유 : Virtual DOM에서 컴포넌트 변화를 감지할 때 효율적 비교를 위해 컴포넌트 내부는
DOM 트리 구조 하나여야 한다는 규칙이 있기 때문이다.
import React from 'react';
import Hello from './Hello';
function App() {
return (
<Hello />
<div>안녕히계세요.</div>
);
}
export default App;
///
Failed to compile
Parsing error : adjacent JSX elements must be
wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?
위 코드는 오류가 발생하므로 아래 처럼 변경을 해야 한다.
<div>
<Hello />
<div>안녕하세요</div>
</div>
하지만 이렇게 불필요한 div로 감싸는게 좋지 않은 상황도 있다.
ex) 스타일 설정이 복잡해지고, table 관련 태그 작성 시 내용을 div로 감싸기 애매함.
그럴 땐, 리액트의 Fragment를 사용하면 된다.
import React from 'react';
import Hello from './Hello';
function App() {
return (
<>
<Hello />
<div>안녕히계세요</div>
</>
);
}
export default App;
Fragment를 사용하면 브라우저 상에서 별도의 엘리먼트로 나타나지 않는다.
3. JSX 안에 JS 값 사용하기
내부에서 JS 변수를 보여줘야 할 때는 {}으로 감싸야 한다.
import React from 'react';
import Hello from './Hello';
function App() {
const name = 'react';
return (
<>
<Hello />
<div>{name}</div>
</>
);
}
export default App;
Jsx에서 태그에 style과 CSS class를 설정하는 방법
인라인 스타일은 객체 형태로 작성.
-로 구분되어 있는 이름들은 camelCase 형태로 네이밍
ex) background-color => backgroundColor
CSS class 설정은 className=으로 설정을 해줘야 한다.
이유 : class 키워드는 이미 JS에 존재하는 키워드기 때문이다.
import React from 'react';
import Hello from './Hello';
function App() {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
<Hello />
<div style={style}>{name}</div>
<div className="gray-box"></div>
</>
);
}
export default App;
4. 조건부 렌더링
JSX 내부 JS 표현식에서 if 문 사용 불가.
JSX 밖에서 if문을 사용하거나 { } 안에 삼항 연산자를 사용
const condition = true;
return (
<div>
<h1>리액트 안녕!></h1>
{
condition ? '참' : '거짓'
condition && '보여주세요'
}
</div>
)
'리액트' 카테고리의 다른 글
리액트를 다루는 기술 4장 - 이벤트 핸들링 (0) | 2021.08.18 |
---|---|
리액트를 다루는 기술 3장 - 컴포넌트 (0) | 2021.08.17 |
리액트를 다루는 기술 - props (0) | 2021.08.17 |
- Total
- Today
- Yesterday
- 글로
- inline
- css
- 변수
- 네트워크 프로그래밍
- 알고리즘
- Link
- C언어
- 차이점
- visual studio code
- 문자열
- 생활코딩
- 동영상을
- PHP&MySQL
- php
- 언리얼엔진4
- 조건문
- javascript
- 안드로이드 스튜디오
- 관계형데이터베이스
- 언리얼엔진
- 정렬
- GRID
- HTML
- 기초
- 생활코딩#동영상을#글로#html
- 선택자
- TAG
- 객체
- 생활코딩#MySQL
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |