본문으로 건너뛰기

23.07.02

오늘 한 일

  • CS 스터디 공부

하루 요약

  • 13:00 ~ 17:00 CS 스터디 공부

CS 스터디 공부

CSR

Client Side Rendering

클라이언트 사이드 렌더링의 약자로, 브라우저에서 렌더링하는 방식

동작 방식

  1. 사용자가 웹 페이지를 방문하면(request), 브라우저는 최소한의 HTML 파일을 다운로드(response) 한다. 이 HTML 파일은 script, meta, link 등의 태그를 포함하며, 빈 컨텐츠의 index.html 파일이라고 보면 된다.
  2. 브라우저는 index.html에 있는 자바스크립트 번들 파일을 다운로드한 다음 AJAX를 통해 API 요청을 수행하여 동적 컨텐츠를 가져오고 파싱하여 최종 컨텐츠를 렌더링한다.
  3. 사용자가 페이지를 이동할 경우, 서버에 추가 HTML파일을 요청하지 않고 이미 받은 자바스크립트를 이용하여 렌더링 한다.

장점

  • 초기 로딩 속도가 빠르다.
  • 서버의 부담이 적다. (필요한 부분만 요청하고 응답하기 때문에)
  • 사용자 경험이 좋다. (깜빡임이 없다. 빠른 인터렉션을 제공한다.)

단점

  • SEO(Search Engine Optimization)에 취약하다. (초기 HTML에는 빈 페이지만 존재하기 때문에 검색엔진이 페이지를 수집하기 어렵다.)
  • 초기 로드 속도가 오래 걸린다. (첫 요청 시 필요한 모든 파일을 다운로드 받아야 하기 때문에)

SEO 최적화

  • meta 태그를 넣어준다.
  • sitemap 문서를 작성한다.
  • 시맨틱 태그를 사용한다.
  • 검색엔진에게 페이지를 수집할 수 있도록 robots.txt를 작성한다.

근데 사실 구글 크롤러는 자바스크립트를 실행시켜서 렌더링된 페이지를 수집한다. [네이버의 검색엔진](SPA 기반으로 제작된 사이트의 수집 및 색인을 지원)도 SPA 기반으로 제작된 사이트의 수집 및 색인을 지원하고 있다.

SEO가 아예 안되는 건 아니지만, 검색엔진마다 다르기 때문에 SEO를 잘 최적화 시켜주는 것이 좋다.

초기 로드 속도 최적화

  • 코드 스플리팅을 사용한다.

SSR

Server Side Rendering

서버사이드 렌더링의 약자로, 서버로부터 완전하게 만들어진 html파일을 받아와 페이지 전체를 렌더링하는 방식

동작 방식

  1. 사용자가 웹 페이지를 방문하면(request), 서버는 리소스를 확인하고 페이지 내에 있는 서버측 스크립트를 실행 후 HTML 컨텐츠를 컴파일 및 준비한다.
  2. 컴파일된 HTML은 추가 렌더링 및 표시를 위해 클라이언트 브라우저로 전송된다(response).
  3. 브라우저는 HTML을 다운로드하고 최종 사용자가 사이트를 볼 수 있도록 한다.
  4. 브라우저는 자바스크립트를 다운로드하고 실행하면서 페이지를 대화형(interactive)으로 만든다.
  5. 클라이언트는 필요한 경우 추가적인 데이터를 서버로 요청하여 동적으로 페이지를 업데이트한다.

장점

  • SEO에 유리하다. (서버에서 페이지를 넘겨받기 때문에 각 페이지에 대한 정보를 입력하기 쉽다.)
  • 초기 로딩 속도가 빠르다. (서버로부터 화면을 렌더링 하기 위한 필수적인 요소를 먼저 가져오기 때문에)

단점

  • 초기 로딩 이후 페이지 이동 시 속도가 느리다. (페이지 이동 시마다 서버로부터 새로운 페이지를 받아와야 하기 때문에)
    • TTV(Time To View)와 TTI(Time To Interact) 간의 시간 간격이 존재 (TTV < TTI)
  • 서버의 부담이 크다. (사용자가 요청할 때마다 서버에서 페이지를 렌더링 해야 하기 때문에)
    • TTFB(Time To First Byte)가 길다.
  • 사용자 경험이 좋지 않다. (페이지 이동 시마다 새로고침이 발생하기 때문에 깜빡임이 발생한다.)

최적화

  • 캐싱을 사용한다. (CDN을 사용한다.)
    • 동일한 요청에 대한 응답을 캐싱하여 서버의 부담을 줄인다. -> TTFB 감소, 렌더링 속도 증가

React에서 상태 관리 라이브러리를 쓰는 이유?

React는 여러 컴포넌트로 구성되어있다. 각각의 컴포넌트마다 state가 있을 수 있고, useState 같은 hook으로 상태를 관리할 수 있다.

state가 변경되면 컴포넌트가 리렌더링되어 변하게 된다.

리액트는 단방향 데이터 흐름, 즉 부모 -> 자식으로만 데이터가 전달이 가능하기 때문에 자식 컴포넌트도 state에 맞게 변경하려고 한다면 props로 전달해야 한다.

만약 자식 컴포넌트에서도 props로 받은 state를 변경가능하게 하려면 state 변경 함수 또한 props로 전달받아야 한다.

// 부모 컴포넌트
function ParentComponent() {
const [name, setName] = useState('Parent Name');

return <ChildComponent name={name} setName={setName} />;
}

// 자식 컴포넌트
function ChildComponent(props) {
return (
<div>
<p>부모 이름:{props.name}</p>
<button onClick={() => props.setName('')}>초기화</button>
</div>
);
}

위 코드에서는 state를 공유하기 위해 부모에서 자식 컴포넌트로 한 번 전달했지만, 만약 그 깊이가 깊어진다면 state 관리가 어렵고 가독성이 떨어질 것이다. 이것을 과도한 props drilling이라고 한다.

이 문제를 해결하기 위해 전역 상태를 관리하는 라이브러리를 사용하게 된다.

많은 전역 상태 라이브러리들이 있는데, 그 중 Redux를 알아보자.

Redux

자바스크립트 앱을 위한 예측 가능한 상태 컨테이너

Redux는 자바스크립트 앱이 점차 고도화 되고, 그에 따라 복잡해지는 데이터를 통제하기 위해 고안된 Flux 패턴 기반의 구현체이다.

데이터의 변경은 반드시 발행된 Action에 의해 순수 함수인 Reducer 내에서 일어나야 하며, 단방향으로만((View → Action + Dispatcher → Middleware → Reducer → Store) → View) 일어난다.

Redux의 3가지 원칙

  1. Single source of truth: 애플리케이션의 상태는 하나의 스토어에 하나의 객체 트리 구조로 저장된다.
  2. State is read-only: 상태는 불변 객체로 관리되어야 한다.
  3. Changes are made with pure functions: 상태를 변경하는 함수는 순수 함수여야 한다.

Redux의 3가지 원칙을 지키는 방법

  1. Action: 상태를 변경하는 유일한 방법이자, 상태에 어떤 변화가 필요한지 알리는 객체
  2. Reducer: 변화를 일으키는 함수로, 이전 상태와 액션을 받아 새로운 상태를 반환한다.
  3. Store: 애플리케이션의 상태와 리듀서가 들어있는 객체

Redux의 흐름

  • View에서 유저가 일으키는 행동에 맞게 Action 객체가 생성
  • Action은 Dispatcher를 통해 Reducer로 전달
  • Action의 type에 따라 Reducer 내에 미리 정해져 있던 로직이 Store를 변경
  • 변경된 Store의 내용이 View로 반영

내일 할 일

  • Rust 스터디 준비
  • 함수형 프로그래밍 스터디 공부
  • Dogsounds TIL SEO 작업, GA4 적용, Algolia 문제 해결