728x90

들어가며...

useNavigation훅을 통해서 상태를 저장할 수 있습니다. 해당 상태는 uri에 직접적으로 반영이 되지 않는 상태입니다.
따라서  새로고침 시 막연하게 초기화 될 거라고 생각을 했었습니다. 하지만 실제 테스트 해 본 결과 상태가 초기화가 되지 않았습니다. 심지어 ChagGPT 조차 상태가 초기화 된다고 하더군요..



import { useNavigate } from 'react-router';

const Home = () => {
  const navigate = useNavigate();

  return (
    <div>
      <h1>Home</h1>
      <button
        onClick={() => navigate('/test', { state: { message: '저장됨' } })}
      >
        Test 페이지로 이동
      </button>
    </div>
  );
};

export default Home;

 

message에 저장됨이라는 상태를 여전히 가지고 있었습니다. useNavigate훅은 결국 History API 기반의 라이브러리 이기에 혹시 HTML 파일에서도 확인해보았고 여전히 초기화되지 않음을 확인하였습니다.

 

따라서 History API의 state의 스펙에 대해서 알아보기로 생각을 하였습니다.

결론은 브라우저에서는 Session History에  상태를 기록을 하는데, 해당 상태는 복원이 가능해야 합니다. 따라서 메모리에 기록이 되어야 하기 때문에, 새로고침을 하여도 다른 탭을 열거나 기존 탭을 닫는 방식이 아니면 상태가 유지가 됩니다.


History에 대해서

시작점은 History였습니다. 당연히 MDN에는 상태의 생명주기에 대한 언급이 있지 않을까라는 막연한 기대감에 접근하게 되었습니다.

History API는 history 전역 객체를 통해 브라우저 세션 히스토리(웹 익스텐션 히스토리와 혼동해서는 안 됩니다.)에 대한 접근을 제공합니다. 사용자의 방문 기록을 앞뒤로 탐색하고, 방문 기록 스택의 내용을 조작할 수 있는 유용한 메서드와 속성을 노출합니다.

 

해당 문서에서 History State에  대해 찾아보니 "History.state 속성은 현 history에 해당하는 state값을 나타냅니다." 라는 내용이 끝이더군요.

따라서 더 깊게 파고들기 위해서는 HTML의 History 스펙을 확인할 필요가 있었습니다.

history.state : Returns the classic history API state of the active session history entry, deserialized into a JavaScript value.

 

이제 Session history에 대해서 뭔저 알 필요가 생겼네요.

 

세션 히스토리 엔트리는 여러 가지 데이터를 포함하는 구조체(struct)로, 다음과 같은 요소를 가집니다.

  • step: 방문 순서를 나타내는 0 이상의 정수 또는 "pending"(초기값 "pending").
  • URL: 해당 히스토리 엔트리에 저장된 페이지의 URL.
  • document state: 해당 페이지의 문서 상태.
  • classic history API state: window.history.pushState()나 window.history.replaceState()를 통해 저장된 직렬화된 상태 데이터. 기본적으로 StructuredSerializeForStorage(null)로 초기화됨.
  • navigation API state: 네비게이션 API 관련 직렬화된 상태 데이터. 초기값은 StructuredSerializeForStorage(undefined).
  • navigation API key: 네비게이션 API에서 사용하는 UUID(고유 식별자).
  • navigation API ID: 개별 네비게이션 요청을 구분하는 또 다른 UUID(고유 식별자).
  • scroll restoration mode: 스크롤 복원 방식 ("auto"가 기본값).
  • scroll position data: 문서에서 스크롤이 복원될 위치 데이터.
  • persisted user state: 사용자가 입력한 데이터 등 브라우저가 유지할 상태 (기본값 null).

history의 state의 경우에 Session history에 보관되고 있습니다. 이때 직렬화를 거치는데 직렬화를 2가지 목적으로 사용됩니다.

 

1. 미리 처리된(preparsed) 상태를 URL에 저장하는 것

  • 간단한 경우에는, URL에 상태를 저장하면 개발자가 따로 파싱(parsing) 하지 않아도 된다.
  • 다만, URL이 사용자들 사이에서 공유될 수도 있으므로, 어떤 경우든 결국에는 파싱이 필요하다.
  • 하지만 URL에 저장된 상태를 빠르게 가져올 수 있으므로, 약간의 최적화 효과가 있다.

2. URL에 저장하지 않고, 현재 문서(Document)에서만 필요한 상태를 저장하는 것

  • 특정 상태는 새로운 문서가 열리면 다시 생성해야 하므로 URL에 저장하기 적절하지 않다.
  • 이런 경우, 직렬화된 상태를 이용해 브라우저 히스토리에서 해당 상태를 보존하고 복원할 수 있다.

 

이후 공식스펙에는 7.4.6.5 Persisted history entry state 이 존재하는데, 유저의 편의를 위해 히스토리를 복원할 수 있는 방법이 존재해야 합니다.

 

공식스펙을 확인했지만,, 아직까지 왜 새로고침 시에도 값이 유지되는지에 대해서는 명확하지 않습니다.

이를 위해서 크롬에서는 세션 히스토리를 어떻게 사용하는지에 대해서 확인해보았습니다.

 

크롬의 History Session

브라우저의 세션 히스토리는 각 탭에서 발생한 탐색을 추적하여 뒤로 가기/앞으로 가기 탐색과 세션 복원을 지원한다. 이는 chrome://history 같은 기록(history)과는 다른데, 기록은 프로필의 수명 동안 사용자가 방문한 주요 프레임의 URL을 모든 탭에 걸쳐 저장한다.

 

위에서 스펙에서 확인한대로 복원 기능을 가지고 있네요.

 

그리고 복원 기능에 대해서 확인하면 아래와 같습니다.

탭의 공동 세션 히스토리는 유지되므로, Chromium을 다시 시작하거나, 탭을 닫은 후, 또는 다른 기기에서 탭을 복원할 수 있다. 이를 위해 각 NavigationEntry와 그 내부 FrameNavigationEntries 트리의 상태를 PageState 객체 및 기타 메타데이터를 사용하여 직렬화해야 한다. 새로운 값을 안전하게 저장하고 복원하는 방법에 대해서는 Modifying Session History Serialization을 참고하라.

 

마지막으로  Modifying Session History Serialization 에서 직렬화 방법을 변경시 디스크에 남아있는 데이터에 의한 호완 문제가 생길 수 있다는 점을 경고하고 있는데, 이를 통해서 크롬에서 disk에 Session History가 저장되어있음을 알 수 있습니다. 따라서 새로고침시에도 History.state가 유지가 됩니다. 

Note that changing the serialization format is high risk and should be approached carefully. Mistakes or missed steps can cause backwards compatibility problems, because the effects can continue to live on disk between different versions of Chromium

 

 

느낀점

사실 처음에는 History.state의 생명주기 라고 검색하면 금방 해결할 수 있는 지식이라 생각했습니다. 하지만 관련 키워드로는 검색했을 때 나오지 않더군요. 공식 스펙을 보는 것도 제로초님이 영상에서 보시는 걸 본적은 있지만 직접 본 적은 없어서 많이 어렵게 느껴졌네요. 해당 스펙이 존재한다는 것이 명시되었을 뿐 어떻게 구현할 지는 브라우저마다 다를 수 있다는 사실도 어려웠습니다. 영어를 번역하면서 열심히 읽었는데, 혹시 오역이 있었을까에 대한 막연한 걱정도 조금 남아있네요. 혹시 잘못된 부분이 있으면 지적부탁드립니다 ㅠ

 

그래도 덕분에 history가 트리구조가 아니라 리스트 구조가 되었다는 등 많은 정보도 확인할 수 있었네요..
또한 ChatGpt 를 사용할 떄 좀 더 유의할 필요성을 느꼈습니다.  사실 새로고침 시 history.state가 초기화 되는지 여부 정보는 고차원적인 지식은 아니라 생각했는데 ChatGpt가 잘못 알려주더군요.
그리고 확실하게 새로고침에서 history.state가 사라지진 않는다는 지식을 얻어가네요.

참고링크

.https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/modifying_session_history_serialization.md

 

Chromium Docs - Modifying Session History Serialization

Modifying Session History Serialization Note: Please expand these steps as needed. See also NavigationEntryImpl comments for how to save and restore values outside of PageState, which is less common. Overview The following (non-exhaustive) steps are requir

chromium.googlesource.com

https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-history-interface

 

HTML Standard

 

html.spec.whatwg.org

https://developer.mozilla.org/ko/docs/Web/API/History

 

History - Web API | MDN

History 인터페이스는 브라우저의 세션 기록, 즉 현재 페이지를 불러온 탭 또는 프레임의 방문 기록을 조작할 수 있는 방법을 제공합니다.

developer.mozilla.org

https://chromium.googlesource.com/chromium/src/+/master/docs/session_history.md#persistencehttps://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/modifying_session_history_serialization.md

 

Chromium Docs - Modifying Session History Serialization

Modifying Session History Serialization Note: Please expand these steps as needed. See also NavigationEntryImpl comments for how to save and restore values outside of PageState, which is less common. Overview The following (non-exhaustive) steps are requir

chromium.googlesource.com

 

728x90

과거에 next.js의 튜토리얼을 진행하면서 얕게 streaming에 대해 학습한 적이 있습니다. 그 당시에 깊게 이해하지 못한 부분에 대해서 다시 한번 정리하고자 포스팅을 작성하게 되었습니다.

 

전통적인 SSR의 단점

SSR은 서버에서 완성된 HTML을 클라이언트에 전송해줍니다. SSR이 진행되는 과정은 아래와 같습니다.

1. 먼저, 특정 페이지에 필요한 모든 데이터가 서버에서 가져와집니다.
2. 그런 다음, 서버에서 해당 페이지의 HTML을 렌더링합니다.
3. 이후, 페이지의 HTML, CSS, 그리고 JavaScript가 클라이언트로 전송됩니다.
4. 전송된 HTML과 CSS를 사용하여 비상호작용 UI가 화면에 표시됩니다.
5. 마지막으로, React가 UI를 하이드레이션(hydration) 하여 상호작용할 수 있도록 만듭니다.

그렇기에 한 페이지 내에서도 모든 구역이 동시에 작업이 완료되진 않습니다. 하지만 우린 완성된 HTML을 받기 때문에, 하나라도 오래 걸리는 작업이 생기면 HTML을 받지 못하는 문제점을 겪게 됩니다.

출처 : https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming#what-is-streaming

 

 

이를 보완해주는 것이 Next.js의 Streaming 기능입니다.

 

Streaming이란?

Next.js에서는 Streaming을 아래와 같이 정의합니다

Streaming 데이터를 전송하는 기술로, 하나의 라우트를 더 작은 "청크(chunks)"로 분할하여 서버에서 클라이언트로 준비되는 대로 점진적으로 스트리밍할 수 있도록 합니다.
Streaming is a data transfer technique that allows you to break down a route into smaller "chunks" and progressively stream them from the server to the client as they become ready.

 

 

그 결과  Time To First Byte (TTFB) , First Contentful Paint (FCP) ,Time to Interactive (TTI) 를 향상 시킬 수 있습니다.

 

상호작용 시작 시간  |  Lighthouse  |  Chrome for Developers

Lighthouse의 상호작용 시작 시간 측정항목과 이 측정항목을 측정하고 최적화하는 방법을 알아보세요.

developer.chrome.com

 

Streaming 사용방법

Streaming은 크게 2가지의 경우로 사용법이 구분됩니다.

1. 페이지단위로 사용하기

2. 컴퍼넌트단위로 사용하기

 

1. 페이지 단위로 사용하기

export default function Loading() {
  // You can add any UI inside Loading, including a Skeleton.
  return <LoadingSkeleton />
}

 

Lodaing.tsx 파일은 React Suspense를 기반으로 하는 Next.js의 특별한 파일로, 페이지 콘텐츠가 로드되는 동안 대신 표시할 Fallback UI를 생성할 수 있도록 해줍니다. 보통 Layout.tsx에 위치합니다.

 

2. 컴퍼넌트 단위로 사용하기

import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'
 
export default function Posts() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
    </section>
  )
}

 

이 경우에는 react에서 제공하는 Suspense를 활용하여 Streaming을 사용할 수 있습니다.

 

 

 

참고 링크

 

https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming#what-is-streaming

 

Routing: Loading UI and Streaming | Next.js

Built on top of Suspense, Loading UI allows you to create a fallback for specific route segments, and automatically stream content as it becomes ready.

nextjs.org

https://nextjs.org/learn/dashboard-app/streaming

 

App Router: Streaming | Next.js

Improve your application's loading experience with streaming and loading skeletons.

nextjs.org

 

 

 

 

728x90

3d 오브젝트를 만드는데는 여러 프로그램이 있습니다. 이중에서 오픈소스 기반 무료인 blender를 통해서 원하는 오브젝트를 만들고, 최종적으로 gltf 혹은 glb파일을 만들어서 웹에 애니메이션 효과를 주고자 배우기 시작하게 되었습니다.

 

 

 

3d viewport  : 왼쪽 오브젝트들이 존재하는 격자가 존재하는 공간으로, 3d 오브젝트를 시각적으로 보여주는 공간

Outliner : 우측 상단에  Camera cube등이 표시된 공간이며  존재하는 3d오브젝트에 대한 개요를 보여줌

Property Editor : 우측 하단의 각각의 오브젝트 클릭시 적용할 수 있는 editor 및 옵션들이 나오는 영역

 

 Viewport 화면 전환

마우스 휠 : 화면 확대/축소

마우스 휠 + 이동  :  Viewport 화면 각도 제어
Shift + 마우스 휠  + 이동 : Viewport 화면 xyz축 제어

Number pad 1~9 :  특정 xyz축 각도에 대해서 이동

 

 

Object 이동 회전  크기  변형

이동 : G . 회전 : R , 크기 : S , 변형 : T

좌측 버튼을 클릭 시 원하는 기능 선택 가능 가능함. 이때 N을 누를 경우 object의 세부 정보 확인 가능

G가 적용된 상태에서 x,y,z를 누르면 각각 x,y,z축에 대한 기능 적용 가능

초기화는 Alt+ 각각의 단축키 (ex : alt+g 는 이동 초기화)

여러 Object  클릭하기

드래그를 통해 클릭하기 or  shift하고 각각 클릭하기

 

Object  생성하기

상단 add를 통해서 오브젝트를 추가할 수 있습니다. 단축키로는 Shift + a 로 생성할 수 있습니다

이때 신규 오브젝트는  Cursor(분홍 동그라미)의 위치에 생성됩니다. 이떄 cursor는 Shitt + S로 오리진으로 이동시킬 수 있습니다.

 

Snap 기능

G로 오브젝트 이동중에 G + B를 누르면 스냅 기능이 적용되며 다른 오브젝트에 붙일 때 사용할 수 있다.

 

 

Shading

Shading : 오브젝트에 색깔과 재질을 입히는 작업

상단 shading 탭을 클릭하여 작업 가능함

6시 하단의 하나하나의 창을  node라고 하며, 새로 추가한 오브젝트의 경우에는 클릭 시 new 버튼을 통해 추가할 수 있다.

 

basic color : 색 조정

metallic : 금속 느낌 (0~1)

Roughness : 표면 거칠기와 반사조절

 

마우스 올리고 백스페이스 누를 경우 기본값으로 초기화됨

이때 오브젝트끼리 동일한 material을 공유할 수 있음

 

Shading 탭에서 상단을 보면 위측에 4개의 버튼을 확인할 수 있습니다

각각의 버튼을 통해서 Viewport에 보이는 화면을 다르게 할 수 있습니다.

좌측에서 우측으로 갈 수록 실제 화면과 유사해집니다. 대신 컴퓨터 리소스를 많이 사용하게 됩니다.

+ Recent posts