SPA 비동기 데이터 흐름

🐋 SPA 비동기 데이터 흐름

현재 저는 회사에서 ReactTypeScript로 개발을 진행하고 있습니다. 전역 상태관리 라이브러리는 ReduxContext API 등을 사용하고 있습니다. 그러나 제가 담당하고 있는 이력, 결제, 정산 등의 도메인에서는 전역으로 상태관리를 할 정도로 복잡한 구조는 아니어서 실제로 사용하는 경우는 드물다고 할 수 있습니다.

오늘은 회사에서 프로젝트를 진행하면서 현재 사용하고 있는 SPA인 React에서 서버와의 데이터를 주고 받음에 있어서 Data flow를 어떻게 가져가야 좋은가에 대해 이야기를 하게 되었습니다. 데이터의 흐름은 단방향이다라는 개념은 React를 공부하면서 처음 배웠던 개념이지만, 이에 대해 깊게 공부하지는 않았기에 할 말이 없어 개인적으로 공부를 해야겠다고 생각했습니다.

결국, 프론트엔드는 백엔드의 데이터를 받은 후, 이를 가공하여 사용자에게 어떠한 방식으로 전달하느냐에 따라 달려있다고 볼 수 있으므로 궁극적으로 전체적인 프론트엔드 개발을 관통하는 주제라 생각하게 되었고 이를 주제로 정리하려 합니다.

1. Single Page Application

먼저, SPA라 불리는 Single Page Application 에 대해 간단히 짚고 넘어가고자 합니다. 해당 기술이 나오기 전인 전통적인 웹은 정적인 웹페이지로서 페이지 이동을 하게 되면, 서버에 요청을 하고 서버에서 HTML 파일을 클라이언트에 보내주고, 브라우저가 HTML을 반영하여 보여주기 전 새로고침이 일어났습니다.

이는 클라이언트에게 제공하기 위해 미리 작성되어 서비스되는 HTML 문서라고 정의합니다. 이는 사용성이 좋지 않으며, 변경이 필요없는 부분까지도 전체 페이지를 갱신하므로 비효율적이었다고 볼 수 있습니다.

SPA는 위에 설명한 고전 웹 구조의 단점을 극복하고, 성능상 및 효율상의 장점을 가집니다. 가장 큰 장점으로는 SPA 자체라기보다는 화면과 데이터 서비스의 분리라고 할 수 있는데, 이렇게 되면 하나의 서버 기능을 통하여, 그 데이터를 가공하여 무수한 표현 방식을 지닌 다양한 화면 표현 프로그램에 호환이 되도록 할 수 있습니다.

{
  "id" : "orosy",
  "phone": "010-1234-5678",
  "rank": 1,
}

서버는 이전처럼 웹 페이지를 보내주는 것이 아니라, 주소 체계에 따라서 위와 같이 보다 근본적이고 범용적인 데이터를 제공함으로써 다른 프로세스에서 쉽게 이 데이터를 활용할 수 있게 되는 것입니다.

2. JSON

이는 JSON이라 불리는 데이터를 간단하고 명료하게 표현하기 위한 방식입니다. 객체 안에 Key와 Value로 표현되는 데이터의 묶음이죠. 특별한 것은 없고, 단순히 데이터를 표현하는 텍스트 표현법으로 html이나 xml과 같이 정보를 표현하고 저장하는 규격일 뿐이라 할 수 있습니다.

클라이언트가 서버로 정보를 요청했을 때 서버가 html 파일이 아니라 위와 같은 JSON 형태로 간편하게 정보를 보내준다면, 클라이언트 측의 자바스크립트는 id가 orosy이고, 전화번호가 010-1234-5678이라는 등의 정보를 이용하여, 로그인 상태 화면의 DOM 객체를 실시간으로 변형시키는 등의 일을 통해 정보를 활용할 수 있는 것입니다.

페이지 이동 시에 변경되는 부분만 JSON으로 받아온 뒤, 브라우저의 자바스크립트에서 받은 JSON을 토대로 DOM에 변경된 부분만 렌더링합니다. 필요한 부분만 갱신하기 때문에 네이티브 앱에 가까운 자연스러운 페이지 이동과 사용자 경험을 제공할 수 있습니다.

이를 그림으로 표현하면 다음과 같습니다.

3. DOM

여기서 DOM이란 용어가 나오는데 이에 대해 간단히 정리하자면 다음과 같습니다.

  • 브라우저 객체 모델(BOM, Browser Object Model) : 브라우저와 관련된 객체들의 집합
  • 문서 객체 모델(DOM, Document Object Model) : HTML, XML 문서에 접근하기 위한 일종의 인터페이스. HTML, CSS가 사용자에게 직접적으로 보이는 것이라면, DOM은 기계나 소프트웨어가 웹 사이트 구조를 어떻게 이해하는 지에 대한 표준

이제 화면에 관련된 요소들은 자바스크립트가 DOM과 같은 객체를 이용하여 쉽고 동적으로 변화시킬수 있으니, 남은 것은 그저 서버에게 정보를 받아와서 그 부분에만 동적인 변화를 하도록 만들면 되는 것입니다. 그것이 위에 설명하는 JSON 데이터가 되는 것입니다.

그렇다면, 서버에서 JSON 데이터를 받아오기 위한 AJAX는 무엇일까요?

4. AJAX

AJAXAsynchronous Javascript And Xml의 약자로 비동기 통신을 의미합니다.

데이터를 이동하고 화면을 구성하는데 있어 화면 갱신 없이 JavaScript 을 이용해서 필요한 데이터를 서버로 보내고 응답을 가져오는 방법입니다. 즉, JavaScript를 통해서 서버에 데이터를 비동기 방식으로 요청하는 것입니다.

HTTP Client를 내장하고 있는 Angular와 다르게, React는 따로 내장 클래스가 존재하지 않습니다. 따라서 React에서 AJAX를 구현하려면 JavaScript 내장 객체인 XML Request를 사용하거나 다른 HTTP Client를 사용해야 합니다. 이중 가장 많이 사용되는 것이 Axios입니다.

Axios란?

AxiosNodeJs브라우저를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리입니다. 해당 정보를 불러오는 API를 부르기 위해 다음과 같이 사용합니다.

import axios from 'axios';

const fetchDetail = (id) => {
    return axios.get(`${context}/sample/${id}`);
};

5. 중간 정리

그렇다면, 중간 정리를 해보도록 하겠습니다. 위에서 이야기한 개념들과 함께 SPA 구동이 어떠한 순서대로 진행되는지 알아보겠습니다.

  1. 클라이언트가 대기 중인 서버로 요청을 보냅니다.

  2. 서버는 클라이언트에게 가장 먼저 HTML 웹페이지와 JS, CSS 파일 등을 보냅니다.
    클라이언트에게 재료를 던져준 것이라 할 수 있고, 이것이 바로 서버가 처음 제공하는 Single Page입니다.

  3. 클라이언트가 Single Page에서 제공하는 서비스를 미리 설계한 API에 맞게 클릭하거나 요청하면 서버가 미리 정의된 기능에 따라서 그 요청을 실행시켜 줍니다. 다만, 화면에 대한 제공은 한번 뿐이며, 나머지는 JSON에 의한 데이터를 전송합니다.

  4. 바로 그러한 서버 데이터를 받아들여, 클라이언트 측의 자바스크립트는 동적으로 화면을 변화시키면서 한 화면임에도 모든 기능을 수행하고 표현이 가능하게 됩니다.

6. React 데이터 흐름

지금까지 SPA에 대해 이야기한 것과 같은 궤를 같이 하는 React 개발 방식의 가장 큰 특징은 페이지 단위가 아닌 컴포넌트 단위로 시작한다는 점입니다.

따라서, 먼저 컴포넌트를 만들고 다시 페이지를 만드는 상향식(bottom-up) 방법을 사용합니다. 이것의 가장 큰 장점은 테스트가 쉽고 확장성이 좋다는 점입니다. 그렇다면, 이러한 방법으로 데이터는 어디에 둘 것인지 생각해야 합니다.

데이터는 어디에 둘 것인가

컴포넌트는 바깥에서 props를 이용해서 데이터를 마치 인자(arguments) 혹은 속성(attributes)처럼 전달 받을 수 있습니다. 이러한 데이터를 전달하는 주체는 부모 컴포넌트가 됩니다.

이는 데이터 흐름이 하향식(top-down)임을 뜻합니다. 이 원칙은 단방향 데이터 흐름(one-way data flow)라는 키워드로 통합니다. 그리고 컴포넌트는 props를 통해 전달받은 데이터가 어디서 왔는지 전혀 알지 못합니다.

Data Fetching

React라는 SPA(Single Page Application)들이 탄생하게 되어서 우리의 코드는 예전보다 더 많은 상태를 관리하게 되었습니다. 클라이언트가 서버에 데이터를 요청하고 fetching 하여 state를 변화시키는 과정에서 비동기가 발생하게 됩니다.

항상 변화하는 state를 관리하기란 쉽지 않습니다. 이벤트가 수없이도 많이 발생해서 데이터를 바꾸는 Single Page App 에서 언제, 왜, 어떻게 상태가 변화하는지를 감지하기란 힘든 일이기 때문입니다.

복잡하게 느끼는 이유는 두 가지 컨셉을 핸들링해야하기 때문일 것입니다. 사람의 머리로는 이해하기 쉽지 않은 두 가지 컨셉: mutation(변화)asynchronicity(비동기).

멘토스와 코카콜라를 섞으면 폭발하듯, 우리의 머리도 상태의 변화와 비동기를 한 번에 이해하려고 들면 열이 나서 곧장이라도 터질 준비를 합니다. 따로따로 두 가지 개념은 훌륭합니다. 하지만, 함께 하면 엉망진창이 됩니다. React와 같은 라이브러리는 이러한 문제를 해결하기 위해서 View 단에서 비동기와 직접적인 DOM 접근을 막습니다.

그리고 이러한 개념과 더해 컴포넌트의 내부와 외부에서 데이터를 처리하는 방법에 대해 나누어서 생각하게 되면, 더욱 복잡해지게 되는 것입니다. 물론 매우 어렵지만, 간단히 정리하자면 아래와 같다고 할 수 있습니다.

처리 방법장점단점
컴포넌트 내부에서 처리HTTP 요청 빈도를 줄임브라우저의 메모리에 많은 데이터를 갖게 되어서 클라이언트의 부담이 늘어남
컴포넌트 외부에서 처리구현에 대해 생각하지 않아도 됨빈번한 HTTP 요청으로 서버의 부담이 늘어남

짧은 개발자 경력으로 생각한 것은 가급적이면 컴포넌트 외부에서 처리하는 것이 좋다는 것이 저의 의견입니다. 물론, 전역 상태관리 라이브러리라는 것이 있지만 이를 고려하지 않는다고 했을 때에 컴포넌트 내부에서 데이터를 처리하게 된다면, 수없이 많은 컴포넌트를 담고 있는 페이지에서는 함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 Side Effect가 발생할 가능성이 매우 높습니다.

이로 인해, 서버에서 전해주는 데이터가 불변성을 유지하지 못하고 다른 컴포넌트에게도 영향을 주게 되는 심각한 상황으로 번지게 될 수 있기 때문입니다. 그렇기 때문에 최대한 컴포넌트 외부에서 처리하며 데이터의 흐름을 단방향으로 유지하되 서버의 부담을 줄여야 하는 방법을 고려해야 한다고 생각합니다.

그리고 덧붙여 클라이언트가 서버에 요청을 덜 보내기 위해서 DebounceThrottle을 사용하게 되는데 이는 추후 포스팅에서 다루도록 하겠습니다.

오늘은 프론트엔드와 백엔드의 데이터 흐름에 대해 알아보며, React라는 SPA 라이브러리에 대해 함께 알아보았습니다. 마지막에는 다소 정리가 안된 느낌이 들긴 하지만 결국, 결론은 정답은 없다는 것입니다.

데이터를 처리하는 방법에 따라 클라이언트, 서버 각각 부담을 갖게 되는 주체가 달라지며 각 상황에서 이를 해결할 수 있는 더 좋은 방안이 있다면 이를 선택하는 것이 정답일 것입니다. 프로젝트별로 상황별로 모두 달라질 수 있기에 정답이 없는 문제에서 가장 최고의 방법을 강구하는 것이 개발자의 목표가 아닐까하며 오늘은 여기서 글을 마치도록 하겠습니다.

출처

SPA(Single Page Application)란?
SPA(Single Page Application)와 웹프론트 기술
데이터 흐름과 비동기 작업
Redux의 탄생동기와 철학 이해하기

좋은 웹페이지 즐겨찾기