[TIL] React : Basics

20515 단어 ReactTILReact

리액트(React)에 대한 기본적인 내용으로 리액트에 대한 기반 정보컴포넌트, JSX에 대한 내용을 포함합니다. 😊

리액트란 무엇인가? 🔤

험하디 험한 바닐라 자바스크립트를 지나 드디어 리액트에 도착했다. 잠깐 알아봤는데도 이리 어메이징하고 어썸한게 있나 싶다. 그렇다면 리액트는 무엇인가? 페이스북에서 만든건 알겠는데 제대로 알아본 적이 없다. 이번 포스팅에서 간단히 리액트에 대해 알아보고, 어떤 원리로 디스플레이에 반영되는지에 대해서도 Araboza.

리액트(React)는 자바스크립트 라이브러리의 하나로 사용자 인터페이스(UI)를 만들기 위해 사용된다. 앞에서도 말했듯이, 페이스북에 의해 만들어졌고 개별 개발자 및 기업들 공동체에 의해 유지보수 된다.

리액트와 비슷하게 사용되는 Angular, VueMVC(Model-View-Controller) Architecture인데 반해, 리액트는 오직 View 만을 담당하며, 그렇기에 추가적인 third-party 라이브러리(React-router, Redux)를 함께 사용한다.

💡 third-party library

기본적으로 제 3자의 의미를 갖는 'third-party' 가 포함된 'third-party library'는 프로그래밍을 위해 도움이 되는 플러그인이나 라이브러리 등을 말한다.

이에 대한 예시로 리액트의 경우 React-router를 사용하는데, SPA(Single Page Application) 방식을 채택하는 리액트의 경우 MPA(Multi Page Application) 방식처럼 페이지의 이동이 불가피하다. 그렇기에 페이지를 새로 불러 들이지 않고 변경된 부분만 수정하여 하나의 페이지에서 출력하게 해주는 렌더링 라이브러리인 라우터를 사용하는 것이다.


가상 돔(Virtual Dom) 🌐


리액트의 가장 큰 장점 중 하나는 가상 돔(Virtual DOM)을 통해 실제 돔에 접근하는 대신에 추상화 시킨 객체에 접근한다는 것이다. 이 부분이 어떠한 장점을 갖는 지는 다음과 같은 이유가 있다.

위 예시는 UI를 변경하는 과정에서 가상돔과 브라우저의 상태를 보여주는 내용이다. 위 내용을 설명하기에 앞서 실제 돔과 가상 돔의 차이점에 대해 간단히 알아보자. 실제 돔을 조작하는 것은 화면에 실제로 적용하는 과정이기에 이를 진행하는 것은 상대적으로 무거운 프로세스에 속한다. 그렇기 때문에, 이를 직접 조작하는 것 보다 이전에 만들어 놓은 경량 복사본인 가상 돔에 이를 우선적으로 적용하고 실제 돔과 어떠한 차이점이 있는 지 비교하여 돔 조작을 진행하는 것이 보다 더 가벼운 프로세스에 해당하는 것이다.

다시 돌아와서 위 예시를 살펴보면, 우선 상태가 변화된 것을 인지하고 이에 따라 변화한 부분을 추적하여 가상 돔에 적용하였으며 마지막으로 변경 부분에 대해 실제 돔에 적용하여 이를 마무리 짓는다. 이렇게 되면 특히나 사용자의 인터랙션이 많은 SPA(Single Page Application)는 변화의 양이 많기 때문에, 변화의 양을 한꺼번에 묶어서 한 번에 진행하는 형태인 리액트가 훨씬 쾌적한 브라우저 환경을 제공한다.

💡 SPA(Single Page Application)

SPA(Single Page Application)란 서버에서 완전히 새로운 페이지를 불러오지 않고 현재 페이지를 동적으로 다시 작성함으로 페이지를 변경하는 형식을 말한다. 페이스북을 하다보면 다른 사람이 게시물에 댓글을 달았을 때, 별도의 새로고침 없이 업데이트 됨을 볼 수 있었다. 그러한 기능이 가능한 이유는 페이지가 업데이트 될 때, 새로운 문서(HTML)를 다시 스캔하는 것이 아니라, 자바스크립트를 활용하여 다시금 변화가 일어난 부분에 대해서만 수정을 진행하기 때문이다.

SPA와 반대되는 개념으로 MPA(Multi Page Application)가 있는데, 나는 해당 개념을 화이트보드의 갯수로 비유하여 이해하기로 했다. SPA의 경우 화이트보드가 하나고 여러가지 초안을 바꾸면서 수정하는 형식이고, MPA의 경우는 여러가지의 화이트보드에 초안들이 미리 작성되어 있는 상태에서 화이트보드를 변경하는 형식이라고 이해했다.

그렇기에 SPA 형식은 빠른 반응성, 화면 전환 등의 측면에서 사용자 친화적이고 상대적으로 유지보수가 쉽고 개발속도가 빠르며, 전체 트래픽 양이 적다는 장점이 있다.

반면에, 처음 접속과 동시에 모든 리소스를 한 번에 받기 때문에 초기 구동 속도가 느리다는 점과, 검색엔진 최적화(SEO)가 CSR 방식으로 어렵다는 점 등이 단점으로 꼽힌다.


컴포넌트(Component) 🧱

또한 리액트의 장점으로 컴포넌트(Component)를 활용한다는 점이 있다. 컴포넌트란 컴퓨터 소프트웨어에서 다시 사용할 수 있는 범용성을 위해 개발된 소프트웨어 구성 요소를 일컫는다. 그런 의미에서 알 수 있듯이 리액트에서는 반복되는 UI 구성 요소들을 하나의 컴포넌트로 지정하여 반복적인 작업을 방지하고 유지보수에 원활함을 부여한다. 컴포넌트의 특징을 정리하면 다음과 같다.

  • 재활용이 가능하다.
  • 코드 유지보수에 용이하다.
  • 코드 가독성이 높아진다.
  • 컴포넌트 내 컴포넌트를 포함할 수 있다.


이러한 특징 덕분에 컴포넌트를 활용하여 UI 구성을 좀 더 체계적으로, 계획적으로 할 수 있는 것이다.

리액트에는 두 가지의 컴포넌트 선언 방식이 있는데 하나는 클래스(Class)형 컴포넌트 , 나머지 하나는 함수형(Functional) 컴포넌트이다. 클래스형 컴포넌트와 함수형 컴포넌트의 역할은 비슷하지만, 그 선언 방식에서 차이를 보인다.

클래스형 컴포넌트(Class Component)


import React from 'react'

class Component extends React.Component { // extends : 클래스를 다른 클래스의 자식으로
  render() {
    return (
      <div>
        <h1>This is Class Component!</h1>
      </div>
    )
  }
}

export default Component


클래스형 컴포넌트는 보이는 듯이 render() 함수를 사용하고 JSX 를 반환하는 형식을 갖는다. 클래스형 컴포넌트는 다음과 같은 특징을 갖는다.

  • state 기능, lifecycle 기능 등을 사용 가능
  • 임의 메서드 정의 가능

함수형 컴포넌트(Functional Componant)


import React from 'react'

const Component = () => {
  return (
    <div>
      <h1>This is Functional Component!</h1>
    </div>
  )
};

export default Component


함수형 컴포넌트는 클래스형 컴포넌트와 다르게 render() 함수를 사용할 필요 없고, 보다 더 간략하게 컴포넌트를 선언할 수 있다는 장점이 있다. 함수형 컴포넌트의 특징은 다음과 같다.

  • 메모리 자원을 상대적으로 덜 사용한다.
  • 컴포넌트 선언이 편하다.
  • Hook 활용


최근에는 함수형 컴포넌트를 더 선호하는 추세이다.

💡 JSX(JavaScript Syntax Extension)

JSX(JavaScript Syntax Extension)를 간단하게 말하면 "자바스크립트 내부에서 HTML을 사용한 것"이라고 말할 수 있고, 정확히 말하자면 자바스크립트 확장 문법이다.

위 예시들에서 자바스크립트 내부에 HTML 구조의 코드가 작성된 것을 확인할 수 있다. 이렇게 작성된 코드들은 바벨(Babel)이라는 자바스크립트 컴파일러를 통해 일반 자바스크립트 형태의 코드로 변환된다. 이렇게 JSX로 작성하면, DOM과 Event 를 활용하는 것보다 좀 더 직관적으로 확인할 수 있기에, 개발 과정에서 효율을 증가시킨다.

JSX의 문법적 특징으로 자바스크립트 표현을 {} 안에 작성하는 것과, Self Closing tag 그리고 작성할 때, 하나의 컴포넌트는 모든 요소들을 감싸는 하나의 최상위 요소가 존재해야 한다는 점 등이 있다.

// 최상위 요소 있음
return (
  <div>
    <h1>Hello, World!</h1>
    <div>Welcome to JSX!</div>
  </div>
)
// 최상위 요소 없음 : 오류 발생
return (
  <h1>Hello, World!</h1>
  <div>Welcome to JSX!</div>
)


최상위 요소가 존재하지 않는 경우, 다른 태그로 래핑하는 것이 꺼려지는 경우 Fragments를 활용하여 형식상의 래핑을 진행할 수 있다. 그렇게 되면 실제로 렌더링 되고 난 뒤에는 감싸는 태그는 존재하지 않는 결과를 보여준다.

// 최상위 요소 Fragments
return (
  <>
    <h1>Hello, World!</h1>
    <div>Welcome to JSX!</div>
  </>
)

리액트 라우터(react-router) 🗺️

앞에서 SPA 방식에 대해 언급하면서, 관련 개념으로 등장했던 라우터에 대해 알아보자. SPA는 말 그대로 하나의 페이지 만으로 구성된 어플리케이션을 의미하는데, 이것이 곧 한 종류의 화면 만이 존재하는 것은 아니다. 당연히도, SPA 또한 직접 브라우저의 API를 사용하고 상태를 설정해서 다른 뷰를 보여줄 수 있다.

이렇게 다른 주소에 따라 다른 뷰를 보여주는 것을 라우팅(Routing)이라고 하고, 공식은 아니지만 리액트의 경우엔 이제 알아볼 리액트 라우터(react-router)라는 써드 파티 라이브러리를 주로 사용한다.

리액트 라우터 사용법


우선 CRA 프로젝트를 생성했다는 전제 하에 이후의 과정을 알아보자. 리액트 라우터를 사용하기 위해서는 별도의 설치 과정을 필요로 한다.

npm install react-router-dom --save


CRA 프로젝트를 설치하고, 해당 디렉토리로 이동하여, 터미널로 해당 명령어를 실행하여 리액트 라우터를 설치한다. 설치가 끝났다면, 이제 컴포넌트를 구현할 차례다.

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
} from 'react-router-dom';

import Login from './pages/Login/Login';
import Main from './pages/Main/Main';

class Routes extends React.Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="/" component={Login} />
          <Route exact path="/main" component={Main} />
        </Switch>
      </Router>
    )
  }
}

export default Routes;


위 예시는 라우터 컴포넌트를 구현한 예시이다. 우선 최상단에서 리액트 모듈을 불러오고, 라우터에서 BrowserRouter , Switch , Route 를 불러온다. 위 세 가지는 아래의 컴포넌트 생성에 사용될 것이다.

그리고 이어서 페이지에 해당하는 컴포넌트들을 각각의 위치에서 불러온다. 위 예시에선 LoginMain 이라는 컴포넌트를 불러왔다.

그다음에 본격적으로 컴포넌트를 생성한다. 위 예시에선 컴포넌트 생성을 클래스 컴포넌트 방식을 사용하여 생성했다. 우선 Router 로 정의된 BrowserRouter 를 통해 전체 라우트들을 묶어준다. 그리고 그 안에 Switch 를 통해 이동할 Route 들을 묶어준다. 마지막으로 그 내부에 Route 를 작성하는 것으로 컴포넌트 생성을 마친다. 위 예시의 경우 초기 링크Login 으로 설정한다.

이렇게 Routes 컴포넌트를 생성하였으면, index.js 의 렌더링 부분을 변경해준다.

ReactDOM.render(<Routes />, document.getElementById('root'));


위 예시를 보면 Routes 컴포넌트를 렌더링하는 것으로 변경되어있다. 이렇게 설정하면, Routes 컴포넌트 내부에서 설정한 default 값의 링크로 초기 페이지가 설정되고, 이후 <Link> 컴포넌트 혹은 this.props.history.push() 를 통해 페이지를 이동할 수 있다.

💡 <Link> 컴포넌트와 this.props.history.push()

위 두 가지 방법은 리액트 라우터를 이용하여 링크를 이동할 수 있는 두 가지 방법이다. 왜 굳이 두 가지 방법이 존재하는지 사용법과 함께 차이점을 알아보자.

우선 각각의 사용법은 다음과 같다.

// <Link>
// 불러오기
import { Link } from 'react-router-dom'
<Link to="/signup">회원가입</Link>
// this.props.history.push()'
// 불러오기
import { withRouter } from 'react-router-dom'
// 함수 생성
goToMain = () => {
  this.props.history.push('/main');
}
// 이벤트에 추가
<button className="loginBtn" onClick={this.goToMain}>


위에서 볼 수 있는 가장 큰 차이점은 함수를 사용한다는 점일 것이다. Link 의 경우 바로 컴포넌트를 추가하여 이를 조건 없이 바로 실행할 수 있지만, this.props.history.push() 의 경우 함수를 통해 작성하여 해당 과정에서 로직을 추가할 수 있다는 점이 있다. 그렇다, 로직의 추가 가능 유무가 두 가지 방식의 큰 차이점이다.

또한 Link 의 경우, 렌더링 이후 <a> 태그로 변하는데, 사용에 있어 그 차이점이 존재한다. <a> 태그를 포함한 세 가지의 사용 방법은 다음과 같이 정리할 수 있다.

  • Link : 별도의 로직이 필요 없는 페이지 내 이동
    ex) 프로필 확인 등
  • this.props.history.push() : 로직이 필요한 페이지 내 이동
    ex) 로그인 등
  • <a> 태그 : 외부 링크로의 이동

좋은 웹페이지 즐겨찾기