상권's

TIL 28 (정적, 동적 웹사이트, useContext)(2021.11.03) 본문

~2022 작성 글/TIL

TIL 28 (정적, 동적 웹사이트, useContext)(2021.11.03)

라마치 2021. 11. 3. 20:49
-오늘의 코플릿 2021.11.03-
정수를 요소로 갖는 배열을 입력받아 오름차순으로 정렬하여 리턴해야 합니다.
병합 정렬을 구현해야 합니다.
arr.sort 사용은 금지됩니다.
입력으로 주어진 배열은 중첩되지 않은 1차원 배열입니다.
병합 정렬은 표준 라이브러리에서 정렬을 구현할 때 퀵 정렬이나 힙 정렬의 대안으로 사용하는 최적화된 정렬 알고리즘입니다.
병합 정렬은 다음과 같은 알고리즘을 사용합니다.
N의 길이를 가진 배열 리스트를 1의 길이를 가진 "부분 리스트"가 N개 모인 것으로 취급합니다.
인접한 부분 리스트들을 정렬하여 2의 길이를 가진 부분 리스트로 병합합니다.
2의 길이를 가진 인접한 부분 리스트들을 4의 길이를 가진 부분 리스트로 합칩니다.
하나의 정렬된 리스트가 될 때까지 위 과정을 반복합니다.
N이 홀수라면, 첫 번째 병합 때 1의 길이를 가진 부분 리스트를 남깁니다.
병합 정렬은 두 가지 방식으로 구현 가능합니다. 재귀적 접근(위->아래) 그리고 반복적 접근(아래->위)
  // 절반으로 나눠서 front tail 을 만든다.
  // 배열의 길이가 1이 되면 리턴한다
  // 첫번째 요소와 두번째 요소의 크기를 비교하고 바꾼다.

첫 수도코드 => 배열의 길이가 1개씩인 front와 tail의 정렬은 비교해서 push나 unshift를 진행하면 되는데, 이후에 배열의 길이가 길어진다면 비교를 어떻게 하면 좋을 지에 대해서 고민을 했습니다. 처음에는 이중 for문을 통해서 비교를 해볼까라는 고민도 했었지만, 그렇게 된다면 코드가 너무 지저분해질 거 같아 다른 방법을 찾아보았습니다. 

const sort = function(arr1, arr2) {
    let sorted = []
    while(arr1.length && arr2.length ) {
      if( arr1[0] <= arr2[0] ) {
        sorted.push(arr1.shift())
      }
      else {
        sorted.push(arr2.shift())
      }
    }
    return [...sorted, ...arr1, ...arr2]
  }

const mergeSort = function (arr) {
  if ( arr.length === 1 ) return arr;
  
  let middle = parseInt(arr.length / 2)
  let front = arr.slice(0, middle)
  let tail = arr.slice(middle)


  return sort(mergeSort(front), mergeSort(tail))
};

=> sort 라는 함수를 통해서 두 개의 배열을 인자로 받고, 해당 배열의 요소들을 정렬해서 리턴합니다. 그리고 mergeSort 함수를 통해서 배열의 자를 수 있을 만큼 자르고, 매번 front와 tail을 이용해서 sort를 진행합니다. 나누는 부분까지는 구현을 했지만, 다른 함수를 만들어서 진행하는 점, 그리고 shift해서 배열의 길이를 줄여가는 while문 작성을 구현하지 못했다는 점이 아쉽습니다. 이번 코드를 통해서 합병정렬에 대해 학습하고, 구현하지 못했던 부분은 꾸준히 복습해서 비슷한 문제를 만나게 되면 구현할 수 있도록 노력하겠습니다.


정적 웹사이트와 동적 웹사이트

  • 정적 웹사이트: HTML 파일(코드) 자체로 배포되는 사이트 (CSR, Client Side Rendering)
  • 동적 웹사이트: 서버에 의해 HTML 파일이 동적으로 생성되는 사이트 (SSR, Server Side Rendering)

웹사이트 렌더링 방식의 변천

 

AJAX 이전에는 요청에 따라 결과가 변하는 동적인 웹페이지를 만드려면, 서버가 매번 동적으로 생성하는 수 밖에 없었습니다.

 

한편 동적 웹사이트를 받아오기 위해서는, 서버가 HTML의 형태로 브라우저에 제공해주어야만 했기 때문에, 헤더나 푸터 등의 페이지 구성요소의 중복 요청/응답이 빈번했습니다. 따라서, 네트워크 상에서 주고받는 패킷의 크기가 다소 컸습니다.

 

이처럼 AJAX 이전에는 서버에서 웹페이지를 만드는 기술이 보편화되었고, 이러한 동적 웹사이트를 만드는 기술로는 PHP, JSP, ASP 등이 널리 사용되었습니다. (물론 node.js로도 동적 웹페이지를 만드는 것이 가능합니다)

 

그러나, 점차 브라우저의 발달과 AJAX 기술이 보편화되면서, 모든 동적인 정보들을 서버가 부담할 필요는 없게 되었습니다.  필요한 부분만 클라이언트가 요청할 수 있게 되었고, 이로 인해 서버의 부하가 다소 줄어들게 되었습니다.

 

이에 따라 서버는 JSON과 같은 순수한 데이터 포맷만 제공해주는 형태로 흐름이 바뀌기 시작했으며, 클라이언트 사이드, 즉 웹페이지는 자바스크립트와 AJAX 기술을 이용한 보다 고도화된 웹 앱, 즉 Single Page Application으로 변모하기 시작합니다.

 

자바스크립트가 동적인 렌더링을 지원하나, 결국 서버가 웹페이지를 렌더링하지 않으며, HTML/CSS/JS 파일의 소스 코드 그대로 작동하는 특징을 갖고 있기 때문에, 이는 정적 웹사이트입니다.

 

정적 웹사이트의 빌드

이처럼 현대의 웹 앱은 정적 웹페이지와 AJAX 기술을 함께 사용하며, SPA(Single Page Application)으로 변모함에 따라 클라이언트 사이드의 규모가 커지게 되었습니다. 이 때 웹사이트 구성요소를 각 파일로 분리하는 모듈화가 이뤄지게 되며, React와 같은 클라이언트 기술이 발전하면서, 단일 파일로 자바스크립트나 페이지를 만드는 작업은 보다 고도화되기 시작했습니다.

 

고도화된 클라이언트 웹 앱은 수많은 모듈로 이뤄져 있습니다. 이처럼 수많은 모듈을 하나로 묶어주는 작업을 번들링(bundling)이라고 하며, 이 과정에서 JSX 파일과 같이 브라우저에서 자체적으로 해석이 불가능한 다양한 보조 기술들을 브라우저가 해석할 수 있도록 만들어주는 작업들이 수반되었습니다. 이러한 과정을 통칭해 "소프트웨어 빌드"라고 부릅니다. 소프트웨어 빌드는, 소스코드를 실행 가능한 결과물로 변환하는 작업을 의미합니다.

수많은 모듈을 하나의 정적 파일로 만들어내는 번들링 과정 (webpack)

다양한 모듈은 정적 파일들로 결과가 만들어져야만 하며, 따라서 이러한 빌드 과정은 배포에 필수적입니다. 예를 들어, React 프로젝트를 내 로컬 컴퓨터에서 자체적으로 실행하기 위해서는 npm start로 개발 서버를 실행해줘야 하지만, 인터넷 상에 배포하기 위해서는 이러한 개발 서버를 실행할 필요가 없으며, 정적 파일을 호스팅하는 서비스에 결과물만 업로드하면 됩니다.

 

Create React App 등으로 생성한 React 프로젝트의 경우에는, npm build 명령어가 package.json 파일에 포함되어 있으며, 이는 모듈을 정적인 파일로 만들어주게 됩니다.

 

React 프로젝트 생성 툴

React 생태계에는 다양한 프로젝트를 생성 툴이 존재합니다. 이러한 프로젝트 생성 툴의 대표적인 예는, Create React App, Next.js 등이 있습니다.

  • Create React App
  • Next.js

Create React App으로 만든 프로젝트의 경우, react-scripts라는 모듈이 사용되고 있으며, Next.js의 경우 next 모듈이 사용됩니다.

 

빌드 툴

프로젝트 생성 툴의 구성을 조금 더 살펴보면, 내부적으로 다양한 툴의 조합으로 이뤄져있는데, 이러한 툴은 다음과 같은 것들이 있습니다.

바벨 Babel 
최신 자바스크립트 문법을 지원하지 않는 브라우저들을 위해서 최신 자바스크립트 문법을 구형 브라우저에서도 돌 수 있게 변환시켜줌 
 
웹팩 webpack 
웹사이트를 만들 때, 파일, 라이브러리, 프레임워크의 양이 많아지는데, 웹팩을 이용해서 번들(bundle)화 해서 간단하게 만들어준다.  -  create-react-app 을 할 경우, src 폴더를 웹팩이 관리해준다.
  • webpack: 모듈 번들러
  • babel: TypeScript, JSX 등과 같이 브라우저가 지원하지 않는 언어를 JavaScript로 바꿔주는 컴파일러
  • ESLint: 자바스크립트 Code convention 및 문법 검사기
  • Sass, less: CSS Preprocessor

[그림] webpack 및 다른 빌드 툴이 하나의 파일로 번들링하는 과정

 

클라이언트 웹 앱 배포

로컬 환경에서 개발한 코드를 실제 서비스로 만들기 위해서는, 빌드 과정과 이를 웹에 노출시키는 배포 과정을 필요로 합니다. 빌드를 통해 만든 정적 파일이 웹을 통해 제공(serve)되려면, 이러한 정적 파일을 제공하는 웹 서버가 필요합니다.

일반적으로 웹 서버라고 하면 웹 서비스를 제공하는 모든 종류의 서버가 웹 서버일 수 있으나, 특별히 정적 파일을 제공할 수 있도록 서버의 공간을 대여해주는 서비스호스팅 서비스라고 부릅니다.

호스팅 서비스는 단순 파일을 웹에서 접근 가능하게 만들어주며, 동적 웹사이트나 (express 등을 사용한) API 서버를 제공하려면, 별도의 클라우드 컴퓨팅 서비스가 필요합니다.

 

다양한 웹 호스팅 서비스

개발자들이 선호하고, 비교적 낮은 가격에 사용할 수 있는 다양한 웹 호스팅 서비스들이 있습니다.

  • Amazon Web Service (AWS) S3
  • Google Cloud Storage
  • Vercel
  • GitHub Pages
  • Netlify
  • Heroku

useContext 출처

const value = useContext(MyContext);
export let 재고context = React.createContext(); // 같은 변수값을 공유할 범위 생성

context 객체(React.createContext에서 반환된 값)을 받아 그 context의 현재 값을 반환합니다. context의 현재 값은 트리 안에서 이 Hook을 호출하는 컴포넌트에 가장 가까이에 있는 <MyContext.Provider>의 value prop에 의해 결정됩니다.

            <재고context.Provider value={재고}> 
            {/* context를 이용할 곳을 provider를 추가해서 감싸준다. */}
            // 재고라는 변수 안에 들어있는 값들을 이용할 범위에다
            Provider value={변수명} 이렇게 작성해준다
            
             <div className="row">
               { 
                 shoes.map((a,i)=>{
                  return <Card shoes={shoes[i]} i={i} />
                 })
               }
             </div>
            </재고context.Provider>

컴포넌트에서 가장 가까운 <MyContext.Provider>가 갱신되면 이 Hook은 그 MyContext provider에게 전달된 가장 최신의 context value를 사용하여 렌더러를 트리거 합니다. 상위 컴포넌트에서 React.memo 또는 shouldComponentUpdate를 사용하더라도 useContext를 사용하고 있는 컴포넌트 자체에서부터 다시 렌더링됩니다.

let 재고 = useContext(재고context) 
// useContext 내부에 위에서 createContext한 변수를 넣어준다.
// 재고라는 변수를 사용할 컴포넌트에서 import해서 사용한다.

 

useContext로 전달한 인자는 context 객체 그 자체이어야 함을 잊지 마세요.

  • 맞는 사용: useContext(MyContext)
  • 틀린 사용: useContext(MyContext.Consumer)
  • 틀린 사용: useContext(MyContext.Provider)

useContext를 호출한 컴포넌트는 context 값이 변경되면 항상 리렌더링 될 것입니다. 컴포넌트를 리렌더링 하는 것에 비용이 많이 든다면, 메모이제이션을 사용하여 최적화할 수 있습니다.

'~2022 작성 글 > TIL' 카테고리의 다른 글

TIL 30 (React 에러 및 서버 구현 에러) (2021.11.05~2021.11.06)  (0) 2021.11.06
TIL 29 (2021.11.04)  (0) 2021.11.04
TIL 27 (2021.11.02)  (0) 2021.11.02
TIL 26 (Redux) (2021.11.01)  (0) 2021.11.01
TIL 25 (2021.10.31)  (0) 2021.10.31
Comments