4 minute read

React SPA

Achievement Goals

  • SPA(Single-Page Application) 개념을 이해하고 설명할 수 있다.
  • SPA의 장, 단점에 대해 이해하고 설명할 수 있다.
  • 와이어프레임을 보고 어느 부분을 컴포넌트로 구분할 지 스스로 정할 수 있다.

SPA(Single Page Application)는 서버로부터 완전히 새로운 페이지를 불러오는 것이 아니라, 화면을 업데이트 하기 위해 필요한 데이터만 서버에서 전달받아 브라우저에서 해당하는 부분만 업데이트 하는 방식으로 작동하는 웹 애플리케이션이나 웹 사이트를 말한다.

전통적인 웹 페이지는 다음과 같이 구성되어 있다.

기존에는 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아오고, 페이지를 로딩할 때마다 서머에 리소스를 전달받아 해석한 뒤 화면에 출력했다. 지금은 웹에서 제공되는 정보가 많기 때문에 새로운 화면얼 보여줄 때마다 서버에서 모든 뷰를 준비한다면 성능상 문제가 발생할 수 있다.

React는 view 렌더링을 사용자의 브라우저가 담당하도록 하고, 우선 어플리케이션을 브라우저에 불러와서 실행시킨 후에 사용자와의 인터랙션이 발생하면 필요한 부분만 자바스크립트를 사용해 업데이트 해준다. 만약 새로운 데이터가 필요하다면 서버 API를 호출해 필요한 데이터만 새로 불어와 어플리케이션에서 사용할 수 있다.

싱글페이지라고 화면이 한 종류일까? 절대 그렇지 않다. 요즘은 웹에서 제공되는 정보의 양도 어마어마하고 페이지 수도 엄청나게 많다.

다른 조수에 다른 화면을 보여주는 것을 Routing이라고 한다. 리액트 자체에 이 기능이 내장되어 있지는 않다. 그 대신 브라우저의 API를 직접 사용하여 관리학나, 라이브러리를 사용하여 쉽게 구현할 수 있다.

하지만 이러한 SPA에도 단점이 있다. 앱의 규모가 커지면 자바스크립트 파일이 너무 커진다는 것이다. 페이지 로딩시 사용자가 실제로 방문하지 않을 수 도있는 페이지의 스크립트도 불러오기 때문이다. 하지만 코드 스플리팅(code splitting)을 트래픽과 로딩 속도를 개선 할 수 있다.




React Router

Achievement Goals

  • React에서 npm으로 React Router DOM을 설치(npm install react-router-dom)하고 이용할 수 있다.
  • React Router DOM를 이용하여 SPA를 구현할 수 있다.
  • 라우팅 구조를 짤 수 있어야 하고, 이에 필요한 기초 문법들을 사용할 수 있어야 한다.

위에서 언급했듯이 리액트 자체 기능은 아니지만 라우팅 관련 라이브러리인 React-router을 이용해 주소에 따라 다른 뷰를 보여주는 라우팅(Routing)을 사용할 수 있다.

React-router는 서드파티 라이브러리로, 공식 라이브러리는 아니지만 리액트 애플리케이션에서 라우팅 용도로 가장 많이 사용한다. 리액트 라우터를 사용하면 페이지 주소를 변경했을 때 주소에 따라 다른 컴포넌트를 렌더링해주고 주소정보(파라미터, URL쿼리 등)를 컴포넌트의 props로 전달해서 컴포넌트 단에서 주소 상태에 따라 다른 작업을 하도록 설정할 수 있다.

스크린샷 2019-02-11 오전 11.55.51

React Router 자세한 사항은 실습으로 익혀보자.

개발환경 구축

터미널에서 다음 명령어를 실행하자

npx create-react-app simpleroute
cd simpleroute
npm start

Create React App 프로젝트가 잘 생성되었다면 이제 React Router DOM을 설치하자.

npm install react-router-dom

잘 설치됐는지 확인하려면 package.json에서 확인 가능하다.

App.js파일로 가서 최상단에 react-router 라이브러리가 제공하는 컴포넌트들을 사용하기 위한 세팅을 하자.

다음 문구를 최상단에 입력하자.

import React from 'react'
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";

이제 React Router DOM을 사용하여 SPA를 구현하기 위한 모든 준비가 끝났다.

React Router 에서 <a> 태그가 아닌 <Link>를 사용하는 이유가 있나요?

<a>태그는 페이지를 전환하는 과정에서 페이지를 불러오기 때문에 다시 처음부터 렌더링을 시킵니다. 즉, 새로고침 현상이 일어나게 되죠. 하지만 <Link> 컴포넌트는 페이지 전환을 방지하는 기능이 내장되어있기 때문에 SPA를 구현할 수 있습니다.



State & Props

Achievement Goals

  • state, props의 개념에 대해서 이해하고, 실제 프로젝트에 바르게 적용할 수 있다.
  • React 함수 컴포넌트(React Function Component)에서 state hook을 이용하여 state를 정의 및 변경할 수 있다.
  • React 컴포넌트(React Component)에 props를 전달할 수 있다.
  • 이벤트 핸들러 함수를 만들고 React에서 이용할 수 있다.
  • 실제 웹 애플리케이션의 컴포넌트를 보고 어떤 데이터가 state이고 props에 적합한지 판단할 수 있다.
  • 실제 웹 애플리케이션 개발 시 적합한 state와 props의 위치를 스스로 정할 수 있다.
  • React의 단방향 데이터 흐름(One-way data flow)에 대해 자신의 언어로 설명할 수 있다.

props

props와 state는 react에서 데이터를 사용할 때 다루는 개념이다.

props & state

props는 properties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소이다. 외부로부터 부모 컴포넌트로부터 전달받은 값으로 객체의 형태를 가진다. 또한 읽기 전용 객체의 형태로 상위(부모) 컴포넌트에 영향을 주지 않게 설계되어 있다. props를 직접 수정할 수는 없고 상위 컴포넌트에서 전달할 값을 변경하는 방법은 가능하다.


props를 사용하는 방법은 아래와 같이 3단계 순서로 나눌 수 있다.

  1. 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
  2. props를 이용하여 정의된 값과 속성을 전달한다.
  3. 전달받은 props를 렌더링한다.
function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child text={"I'm the eldest child"} />  {/* 전달할 값을 {}로 감싸준다. */}
      <Child />
    </div>
  );
}

function Child(props) {
  console.log("props : ", props);
  return (
    <div className="child">
      <p>{props.text}</p> {/* JS 객체의 value에 접근하는것처럼 dot notation을 이용해 호출한다 */}
    </div>
  );
}

export default Parent;

또 다른 예제를 보자. 여는 태그와 닫는 테그 사이에 value를 넣어 전달할 수도 있다.

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child>I'm the eldest child</Child>
    </div>
  );
}

function Child(props) {
  return (
    <div className="child">
      <p>{props.children}</p>
    </div>
  );
}

export default Parent;

또 다른 예제

const App = () => {
  const itemOne = "React를";
  const itemTwo = "배우고 있습니다.";

  return (
    <div className="App">
      <Learn text1={itemOne} />
      <Learn text2={itemTwo} />
    </div>
  );
};

const Learn = (props) => {
  return (
    <div className="Learn">
      <span>{props.text1}</span> <span>{props.text2}</span>
    </div>
  );
};

export default App;

state

props가 상위 컴포넌트에게 전달받은 값이라면 state는 컴포넌트 내부에서 읽고 또 업데이트 할 수 있는 값을 말한다. React에서는 state를 다루는 방법 중 하나로 useState라는 특별한 함수를 제공한다. useState를 사용하기 위해서 다음과 같이 import를 해야 한다.

import React, { useState } from "react";

이후에 useState를 컴포넌트 안에서 호출한다. useState를 호출한다는 것은 “state”라는 변수를 선언하는 것과 같으며, 변수의 이름은 마음대로 지정할 수 있다. 일반적인 변수는 함수가 끝날 때 사라지지만, state 변수는 React에 의해 함수가 끝나도 사라지지 않는다. useState를 이해하기 쉽게 풀자면 이렇다.

const [state, setState] = useState(initialState);
const [state 저장 변수, state 갱신 함수] = useState(상태 초기 );

사용 예시

import React, { useState } from 'react'

const ExampleComponent = () => {

    // useState 함수의 인자에는 상태의 초깃값을 넣어줍니다. ""
    // 값의 형태는 자유입니다. 숫자, 문자열, 객체, 배열.
    const [name, setName] = useState("");
    const [age, setAge] = useState("");

    const onChangeName = e => {
    	// 이름 값 변경
        setName(e.target.value);
    };
    const onChangeAge = e => {
        // 나이 값 변경
        setAge(e.target.value);
    };

    return (
        <div>
            name: <input value={name} onChange={onChangeName} /><br/>
            age: <input value={age} onChange={onChangeAge} /><br/><br/>
            
            name: {name}<br/>
            age: {age}
        </div>
    )
}
export default ExampleComponent;

좀 더 자세한 사용법은 다음 포스팅에서 Hook를 다루면서 정리해보자.



참고문서

solmii님 블로그

리액트를 다루는 기술

리액트 공식 문서