렌더링 최적화
TanStack Router에는 컴포넌트가 필요한 경우에만 다시 렌더링되도록 하는 여러 최적화가 포함되어 있습니다. 이러한 최적화는 다음과 같습니다.
구조적 공유
TanStack Router는 재렌더링 사이에 가능한 한 많은 참조를 유지하는 "구조적 공유"라는 기법을 사용합니다. 검색 매개변수처럼 URL에 저장되는 상태에 특히 유용합니다.
예를 들어 다음과 같이 details 라우트에서 foo와 bar라는 두 검색 매개변수를 사용한다고 생각해 보겠습니다.
const search = Route.useSearch()
bar만 변경해 /details?foo=f1&bar=b1에서 /details?foo=f1&bar=b2로 탐색하면 search.foo의 참조는 안정적으로 유지되고 search.bar만 교체됩니다.
세밀한 선택자
useRouterState, useSearch 등의 다양한 훅을 사용해 라우터 상태에 접근하고 구독할 수 있습니다. 검색 매개변수의 일부와 같은 라우터 상태의 특정 부분이 변경될 때 특정 컴포넌트만 다시 렌더링하려면 select 속성을 사용한 부분 구독을 사용할 수 있습니다.
// component won't re-render when `bar` changes
const foo = Route.useSearch({ select: ({ foo }) => foo })
세밀한 선택자를 사용한 구조적 공유
select 함수는 라우터 상태에 대해 다양한 계산을 수행할 수 있으므로 객체와 같은 여러 유형의 값을 반환할 수 있습니다. 예를 들어 다음과 같습니다.
const result = Route.useSearch({
select: (search) => {
return {
foo: search.foo,
hello: `hello ${search.foo}`,
}
},
})
이 방식은 작동하지만 select가 호출될 때마다 새 객체를 반환하므로 컴포넌트가 매번 다시 렌더링됩니다.
위에서 설명한 "구조적 공유"를 사용하면 이 재렌더링 문제를 방지할 수 있습니다. 기본적으로 구조적 공유는 하위 호환성을 유지하기 위해 꺼져 있지만, v2에서 변경될 수 있습니다.
세밀한 선택자에서 구조적 공유를 활성화하는 방법은 두 가지입니다.
라우터 옵션에서 기본값으로 활성화
const router = createRouter({
routeTree,
defaultStructuralSharing: true,
})
다음과 같이 훅 사용별로 활성화
const result = Route.useSearch({
select: (search) => {
return {
foo: search.foo,
hello: `hello ${search.foo}`,
}
},
structuralSharing: true,
})
[!IMPORTANT] 구조적 공유는 JSON 호환 데이터에서만 작동합니다. 즉, 구조적 공유가 활성화된 경우
select를 사용해 클래스 인스턴스와 같은 항목을 반환할 수 없습니다.
TanStack Router의 타입 안전 설계에 따라 다음을 시도하면 TypeScript에서 오류가 발생합니다.
const result = Route.useSearch({
select: (search) => {
return {
date: new Date(),
}
},
structuralSharing: true,
})
라우터 옵션에서 구조적 공유가 기본적으로 활성화된 경우 structuralSharing: false로 설정해 이 오류를 방지할 수 있습니다.