React는 현재 현업에서 인기 있는 웹/앱(RN)의 View를 개발할 수 있도록 하는 라이브러리이다.
보통 우리가 생각하는 어플리케이션(웹, 앱 혹은 데스크톱용 소프트웨어)을 만들기 위해서는 사용자가 조작하기 위한 UI(User-Interface), UI를 컨트롤 하기 위한 로직, 데이터를 처리하는 비즈니스 로직 등 3가지 부분으로 개발이 필요하다.
이렇게 특정 부분을 나누어 개발하는 방법론을 *MVC 패턴*, *MVVM패턴* 이라고하며, React.js는 View 즉, 사용자가 조작하기 위한 UI를 만드는 것을 도와주는 라이브러리이다.
React.js를 처음 배우면 React.js의 특징으로 다음과 같은 말을 볼 수 있다.
React는 선언형이다.
React는 컴포넌트 기반으로 재사용성이 뛰어나다.
React는 Virtual DOM(가상돔)기반으로 가볍다.
React 컴포넌트는 state와 props 을 가진다.
우리는 여기에서 다음의 키워드를 얻을 수 있다. 선언형(Declarative), 컴포넌트(Component), 재사용성(Reusable), Virtual DOM(가상돔).
내 생각에 React.js의 본질은 위의 키워드로 모두 설명할 수 있다. 각 키워드들에 대해서 알아보자.
소프트웨어 공학에서 자주 접하게 되는 개념은 패러다임(Paradigm)이다. 즉, 프로그래밍을 어떻게 할 것인가 하는 생각에 대한 논의가 활발하게 이루어진다.
이 중 리액트를 하면 자주 접할 수 있는 패러다임이 선언형 Declartive 프로그래밍과 명령형 Imperative 프로그래밍이다. 이 둘의 차이점에 대한 설명은 좀 더 잘 설명된 글 링크를 남기며, 리액트의 선언적 성격을 보도록 하자.
리액트는 선언형 성격에 맞게 컴포넌트(원하는 결과, 뷰)를 얻기 위해 <tag></tag>
jsx 문법을 통해 구현한다. 즉, jsx를 얻기 위한 알고리즘에 대한 구현을 하지 않는다. (예를 들어, document.createElement나 혹은 해당 컴포넌트의 변경사항을 체크하는 알고리즘, 리-렌더링 여부에 대한 알고리즘을 구현하지 않는다.)
이와 같은 선언형 특성은, 리액트를 사용할 때 화면 설계라는 초점에 맞춰서 개발할 수 있도록 해주므로, 다른 부분에 대한 고민을 최소화 해주어 높은 생산성을 보장할 수 있도록 해준다.
우리는 Component 단위로 개발을 해야한다.
컴포넌트는 독립적인 단위의 소프트웨어 모듈을 말한다. 즉 소프트웨어를 독립적인 하나의 부품으로 만드는 방법이다. 리액트는 웹에서 쓰는 각 요소들을 컴포넌트로 만들 수 있게 해 기존의 UI를 다른 화면에서 다시 쓰거나, 다른 프로젝트에서 다시 쓸 수 있도록 하는 장점(높은 재사용성)을 가진다.
HTML element와 컴포넌트를 비교해서 살펴보자. 먼저, <img src="이미지주소"/>
와 처럼 컴포넌트는 내가 지은 이름으로 태그를 만들 수 있다.
또, img태그에서 src를 설정해준 것처럼 컴포넌트에서도 name을 Mark라고 설정해주었다. img에서는 이미지 주소를 바탕으로 이미지를 그린다, 컴포넌트에서는 해당 태그에 어떤 로직을 작성했는지는 모르겠지만 해당 태그안에서 Mark라는 이름을 사용해서 표현을 한다. HTML에서는 어트리뷰트라고 하지만 컴포넌트에서는 어트리뷰트라 하지 않고 prop이라고 한다. 외부에서 <내가 지은 이름1> 태그 안으로 어떤 데이터를 넣어주고 싶을 때 prop을 사용한다. 여러 개 있을 경우 props라고 한다.
이번에는 <button>버튼</button>
에 주목하자. 버튼 태그 사이의 한글을 읽어들여 렌더링할 때 사용한다. 이는 컴포넌트에서도 마찬가지이다. 컴포넌트 태그 사이에 데이터를 담을 수 있는데 이는 children 이라고 한다. children도 props중 하나이다. <내가 지은 이름>은 prop을을 두개 받았다.
{ prop={false}, children="내용" }
이 객체 이름이 props 이다.
사용자 입장에서는 HTML element와 컴포넌트는 크게 다르지 않다. 그러나 <img>
혹은 <button>
은 이미 어떻게 동작할지 구현되어 있지만 <내가 지은 이름1>
혹은 <내가 지은 이름>
은 어떻게 동작할지 구현되지 않았다. 그렇다면 우리가 할 일은, 즉 컴포넌트 개발자가 해야 할 일은 <내가 지은 이름1>이 props를 받아서 그 안에서 어떻게 표현되고 어떻게 동작할지를 구현하는 것이다.
virtual DOM : 가상 돔
가짜 돔 : 어딘가에 데이터로만 존재하는 것(눈에 보이지 않는다.) 하는 역할이 뭐냐 하면 가상의 트리 구조를 만들고 이를 실제로 브라우저에 그리는게 react
정리하자면 우리가 가짜 돔을 만들고 이를 실제로 브라우저에 그리도록 도와주는 것이 바로 react이다.
진짜 돔 : (개발자 도구로 찍히는) 눈에 보이는 것들
돔을 직접 제어하려고 하면 매번 바뀐 부분을 정확하게 파악해서 바꿔주어야 한다. 그런데 직접 제어하지 않는다면, 우리가 표현하기만 하면(이럴땐 A를, 저럴땐 B를 그려라) 알아서 상태를 비교해서 자동으로 렌더링 해준다. 그런데, 사실 직접 돔을 제어하는 것보다는 속도가 느리다. 그래서 가상 돔을 사용하지 않는 프레임워크가 있는데 이게 바로 Svelte 이다. 시간이 난다면 한 번 배워보는것도 나쁘지 않다.
상태가 변했다(빨간 점) => 상태가 변한 곳과 변한 곳의 자식까지 검사한다.(부모가 바뀌면 자식까지 바뀔 가능성이 있으니까) => 이전 상태와 바뀐게 있는지 검사한 후 달라졌다면 다시 렌더한다.
주의 해야할 점은 빨간색이 아닌 곳은 다시 렌더하지 않는다는 것이다.
JSX는 자바스크립트를 확장한 문법이다. = 자바스크립트이다.
JSX는 템플릿 문자열이 아니라 자바스크립트로 변환되는 코드이다.(babel 혹은 타입스크립트가 변환을 해준다.) 템플릿은 html로 변환된다. 타입스크립트와 리액트가 잘맞는 이유는 JSX와의 호환이 잘되기 때문이다. 왜냐하면 JSX는 자바스크립트의 확장이기 떄문에 문자열을 타입스크립트에 매칭하는 것보다 자바스크립트의 문법을 타입스크립트에 매칭하는게 연역적으로 추론이 가능하다. 문자열을 해석해서 문제가 있는지 확인하는 것은 귀납적으로 진행된다.
이 과정은 CSR만 구현되어 있는 react 페이지를 사용자가 처음 방문할때만 일어난다. 또, 인터넷이 매우 느려야만 눈에 보일 수 있다. 1번과 2번 사이에 한가지 추가되는 일이 있는데 바로 캐싱과정이다. 브라우저 내에서 로컬 캐싱이 되기 때문에 처음 방문할때만 발생하게 되는 것이다.
사실상, 페이지를 렌더하는 것은 SSR방식이지만 react를 실행하는 것은 CSR 방식으로 한다.
리액트의 핵심 모듈 2개로 리액트가 하는 일을 알아보자.
// 1. 리액트 컴포넌트 => HTMLElement 연결하기
import ReactDOM from 'react-dom';
// 2. 리액트 컴포넌트 만들기
import React from 'react';
리액트를 사용하려면 두 개의 모듈(라이브러리)가 필요하다. 2번을 통해 컴포넌트를 생성한다. <Hello name="Mark">
같은 컴포넌트를 만들 수 있다. 만든 컴포넌트로 페이지를 그려야 하는데 이를 도와주는게 1번 ReactDOM이다.
ReactDOM에서 가장 많이 쓰는 함수는 render라는 메서드이다. 무엇을, 어디에 그릴 것인지 지정해준다. 이 render는 프로그램에 진입하는 main에 해당하는 역할을 한다.
ReactDOM.render(
// 무엇을
<HelloMessage name="Taylor" />,
// 어디에
document.getElementById('hello-example'),
);