1. userAgent

  • 사용자가 접속중인 브라우저 , OS, 버전 등의 정보를 담고 있다.
  • 브라우저는 서버에 보내는 모든 요청에 userAgent 문자열이라고 부르는 자신의 정체성을 알리는 헤더를 싣어 보낸다.
  • 이 문자열은 보통 브라우저 종류, 버전 번호, 호스트 운영체제를 포함한다.
  • 클라이언트에서는 Javascript 의 NavigatorId.userAgent 속성을 통해서 userAgent 문자열에 접근 가능하다.

언제 사용할까?

  • 웹 브라우저의 종류가 많고, 각각의 엔진을 사용하던 시절에는 각 브라우저별로 동일한 서비스를 제공하기 위해서 사용되었다.
  • 하지만 현재 대부분의 브라우저들이 크롬/블링크 엔진을 사용하고 있기때문에 현재는 브라우저에 대한 정보보다는 접속한 컴퓨터 OS, 모바일 디바이스를 구분하는 역할로서 많이 쓰인다.
  • 예를들어, 사내 서비스에서는 두가지 목적으로 사용한 경험이 있다.
    • 사용자 접속 환경(모바일/데스크톱)에 대한 로그를 남기기 위해.
    • 모바일 디바이스에서 접속 중인지 여부를 확인하기 위해

ref - https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgent


2. package.json - 의존성 버전 고정하기

사내 프로젝트에서 사용중인 msw 는 0.7.4 버전이다. 그러다보니 어느날 새로운 패키지가 추가되고 나서 아래와 같은 에러가 나면서 msw 모킹함수가 실행이 되지 않았다.😖

Type Error: response2.headers.all is not a function 

조금 찾아보니, msw 하위 의존성인 headers-polyfill 패키지가 3.3.0 버전으로 업그레이드 되어서 난 에러이고, headers-polyfill 패키지는 3.3.0 버전부터 all 메서드들 삭제했다고 한다.😑

https://github.com/mswjs/headers-polyfill/releases/tag/v3.3.0

그래서나는 에러였고, 이를 해결하기 위해서는 하위 의존성인 headers-polyfill 패키지의 버전을 3.3.0 보다 아래로 고정시켜야했다. 이 때 yarn 패키지 매니저에서는, package.json 의 resolution 이라는 필드를 사용하여 의존성 버전을 고정시킬 수 있다. ref - https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/

즉, package.json 의 의존성들의 특정 버전이나 범위를 고정할 수 있다. 위에서 겪었던 문제처럼, 하위 의존성 패키지에 업데이트가 있었는데, 이를 의존하는 패키지가 새로운 버전에 대응되지 않을 때 하위 의존성 패키지의 버전을 고정시키기 위해 사용 가능하다.

찾아보니 요거는 yarn 패키지매니저에서 사용가능한거고, npm이나 pnpm에서는 overrides라는 이름으로 동일한 기능을 지원하고 있다.


3. React- useState의 값은 어디에 저장될까?

useState 내부 코드


function useState(initialState) {
  var dispatcher = resolveDispatcher();
  return dispatcher.useState(initialState);
}
  • useState 뿐만 아니라, 모든 훅의 내부 코드는 위의 형태를 가진다.
  • dispatcher 에는 resolveDispatcher 함수의 결과가 할당 되고, dispatcher의 useState 메서드에 초기값을 전달하고, 반환 된 값을 리턴하고 있다.
function resolveDispatcher() {
  var dispatcher = ReactCurrentDispatcher.current;
  return dispatcher;
}
  • resolveDispatcher 는 ReactCurrentDispatcher 라는 객체의 current 프로퍼티를 반환하고 있는데, 여기서 ReactCurrnetDispatcher 는 전역에 설정되어 있는 객체이다.
  1. 따라서, useState가 반환한 상태의 배열은 전역 객체로부터 오고,
  2. 훅을 호출하면 클로저 동작으로 컴포넌트 밖에 있는 외부 스코프에 존재하는 상태에 접근을 하게 된다.
  3. 따라서, 컴포넌트 내부에서 값을 변경하면 외부의 값이 변경된다.
  4. 따라서 함수 컴포넌트의 바디 전체가 리렌더링이 되어도, 외부 스코프에 있는 값은 유지 된다.

위와 같이 클로저를 사용하여 동작하는 setState를 짤막한 코드로 표현하자면 아래와 같다.

let _value;

export useState(initialValue){
  if (_value === 'undefined') {
    _value = initialValue;
  }
  const setValue = newValue => {
    _value = newValue;
  }
  
  return [_value, setValue];
}

요거는 추후에 더 공부하고 정리하겠다😶


4. useEffect 의 cleanup 실행 시점

  • useEffect 의 cleanup 은 컴포넌트가 unmount 될 때 실행되는게 아니라, 리렌더링 될 때 실행된다.
  • props이 변경 되었을 때의 경우를 대비하여 리렌더링, 즉 컴포넌트가 업데이트 될 때 마다 실행시켜준다.

ref - https://ko.legacy.reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update


5. Trailing slash 란?

next.js 의 소스코드를 살펴보다가 trailing slash 판별 메서드가 있어서 찾아봤다 (꼬리 슬래시?!🤧)

  • trailing slash 란 url 경로 뒤에 오는 슬래시를 지칭한다. https://example.com/
  • trailing slash 는 경로의 표준화와 일관성을 위해서 사용된다.
  • 일부 웹 서버 및 프레임웍에서는 trailing slash 여부에 따라서 url을 다르게 처리하기도 한다.

trailing slash 가 없는 경우

  • 서버는 해당 리소스를 우선적으로 파일로 간주하여 처리한다.
  • https://example.com 이라고 표기 할 경우, 해당 이름의 파일이 있는지 확인한다.
  • 없을 경우 해당 이름의 디렉토리를 확인하고, 디렉토리가 있으면 그 안의 기본파일 (index.html) 을 확인 후 서빙한다.

trailing slash 가 있는 경우

  • 서버는 해당 리소스를 우선적으로 디렉토리로 간주한다.
  • 해당 이름의 디렉토리를 확인하고, 디렉토리가 있으면 그 안의 기본파일 (index.html)을 확인한다.

즉, trailing slash 를 명시해줄 경우 파일 확인 동작을 생략 가능하여 응답 속도가 살짝 빨라질 수 있다.


6. 멱등성(Idempotent)

  • 멱등하다는 것은, 첫번째 수행을 한 뒤 여러차례 적용해도 결과가 변경되지 않는 작업
  • 즉 멱등한 작업은 한 번 수행해도, 여러번 수행해도 결과가 같아야 한다.

멱등한 HTTP 요청

  • GET,PUT,DELETE 처럼 리소스를 조회하거나 대체하는 메서드는 멱등하다.
    • PUT은 여러번 호출 해도, 매번 같은 리소스로 업데이트 되고, DELETE는 열버ㅓㄴ 호출 해도 삭제된 리소스에 대한 결과는 달라지지 않는다.
  • 반면 서버 데이터를 변경하는 POST,PATCH는 호출 할 때 마다 응답이 달라지기 때문에 멱등한 요청이 아니다.

멱등성 보장하기

  • 멱등키를 API 요청에 포함하기
    • 이전 요청과 동일한 멱등키를 가진 요청을 받으면, 서버에서 해당 요청을 중복으로 판단하여 실제로 처리하지 않고, 첫 요청과 같은 응답만 반환하는 방식
  • 요청 본문, URL 쿼리 매개변수, 헤더 중 하나에 멱등키를 보내면 됨 (but IETF 에서는 요청 헤더에 포함시키는 방법 권장.)
Idempotency-Key: {IDEMPOTENCY_KEY}
  • 이 때, 클라이언트에서 보내는 멱등키는 uuid 와 같이 무작위적인 고유한 값이어야 한다.

ref - https://www.tosspayments.com/blog/articles/dev-1?from=category