Docs
Guide
Custom Search Param Serialization

Custom Search Param Serialization

기본적으로, TanStack Router는 JSON.stringifyJSON.parse를 사용하여 URL 검색 매개변수를 자동으로 구문 분석하고 직렬화합니다. 이 과정은 검색 문자열의 이스케이프 및 이스케이프 해제를 포함하며, 검색 객체를 직렬화하고 역직렬화하는 URL 검색 매개변수의 일반적인 관행입니다.

예를 들어, 기본 설정을 사용하여 다음과 같은 검색 객체가 있다면:

const search = {
  page: 1,
  sort: "asc",
  filters: { author: "tanner", min_words: 800 },
};

다음과 같이 직렬화되고 이스케이프된 검색 문자열이 생성됩니다:

?page=1&sort=asc&filters=%7B%22author%22%3A%22tanner%22%2C%22min_words%22%3A800%7D

기본 동작은 다음과 같은 코드로 구현할 수 있습니다:

import {
  createRouter,
  parseSearchWith,
  stringifySearchWith,
} from "@tanstack/react-router";
 
const router = createRouter({
  // ...
  parseSearch: parseSearchWith(JSON.parse),
  stringifySearch: stringifySearchWith(JSON.stringify),
});

그러나 이 기본 동작이 모든 사용 사례에 적합하지 않을 수 있습니다. 예를 들어, base64 인코딩과 같은 다른 직렬화 형식을 사용하거나, query-string (opens in a new tab), JSURL2 (opens in a new tab), 또는 Zipson (opens in a new tab)과 같은 특수 제작된 직렬화/역직렬화 라이브러리를 사용하고 싶을 수 있습니다.

이러한 경우, Router 구성의 parseSearchstringifySearch 옵션에 사용자 정의 직렬화 및 역직렬화 함수를 제공하여 구현할 수 있습니다. 이때, TanStack Router의 내장 헬퍼 함수인 parseSearchWithstringifySearchWith를 사용하면 프로세스를 간소화할 수 있습니다.

[!TIP] 직렬화와 역직렬화에서 중요한 점은 역직렬화 후 동일한 객체를 반환할 수 있어야 한다는 것입니다. 만약 직렬화와 역직렬화 과정이 제대로 이루어지지 않으면 일부 정보가 손실될 수 있습니다. 예를 들어, 중첩 객체를 지원하지 않는 라이브러리를 사용하는 경우, 역직렬화 시 중첩 객체가 손실될 수 있습니다.

검색 매개변수 직렬화 및 역직렬화의 항등성을 보여주는 다이어그램

다음은 TanStack Router에서 검색 매개변수 직렬화를 사용자 정의하는 방법에 대한 몇 가지 예제입니다:

Using Base64

검색 매개변수를 base64로 인코딩하여 브라우저와 URL 확장기 등의 호환성을 극대화하는 것이 일반적입니다. 다음 코드로 구현할 수 있습니다:

import {
  Router,
  parseSearchWith,
  stringifySearchWith,
} from "@tanstack/react-router";
 
const router = createRouter({
  parseSearch: parseSearchWith((value) => JSON.parse(decodeFromBinary(value))),
  stringifySearch: stringifySearchWith((value) =>
    encodeToBinary(JSON.stringify(value))
  ),
});
 
function decodeFromBinary(str: string): string {
  return decodeURIComponent(
    Array.prototype.map
      .call(atob(str), function (c) {
        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
      })
      .join("")
  );
}
 
function encodeToBinary(str: string): string {
  return btoa(
    encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
      return String.fromCharCode(parseInt(p1, 16));
    })
  );
}

이 구성으로 이전 객체를 검색 문자열로 변환하면 다음과 같이 나타납니다:

?page=1&sort=asc&filters=eyJhdXRob3IiOiJ0YW5uZXIiLCJtaW5fd29yZHMiOjgwMH0%3D

Using the query-string library

query-string (opens in a new tab) 라이브러리는 쿼리 문자열을 신뢰성 있게 구문 분석하고 문자열화하는 데 인기 있는 라이브러리입니다. 이를 사용하여 검색 매개변수의 직렬화 형식을 사용자 정의할 수 있습니다:

import { createRouter } from "@tanstack/react-router";
import qs from "query-string";
 
const router = createRouter({
  // ...
  stringifySearch: stringifySearchWith((value) =>
    qs.stringify(value, {
      // ...options
    })
  ),
  parseSearch: parseSearchWith((value) =>
    qs.parse(value, {
      // ...options
    })
  ),
});

이 구성으로 이전 객체를 검색 문자열로 변환하면 다음과 같이 나타납니다:

?page=1&sort=asc&filters=author%3Dtanner%26min_words%3D800

Using the JSURL2 library

JSURL2 (opens in a new tab)는 URL을 읽기 쉽게 유지하면서도 압축할 수 있는 비표준 라이브러리입니다:

import {
  Router,
  parseSearchWith,
  stringifySearchWith,
} from "@tanstack/react-router";
import { parse, stringify } from "jsurl2";
 
const router = createRouter({
  // ...
  parseSearch: parseSearchWith(parse),
  stringifySearch: stringifySearchWith(stringify),
});

이 구성으로 이전 객체를 검색 문자열로 변환하면 다음과 같이 나타납니다:

?page=1&sort=asc&filters=(author~tanner~min*_words~800)~

Using the Zipson library

Zipson (opens in a new tab)은 매우 사용자 친화적이고 런타임 성능과 압축 성능 모두에서 뛰어난 JSON 압축 라이브러리입니다. 다음 코드를 사용하여 검색 매개변수를 압축할 수 있습니다:

import {
  Router,
  parseSearchWith,
  stringifySearchWith,
} from "@tanstack/react-router";
import { stringify, parse } from "zipson";
 
const router = createRouter({
  parseSearch: parseSearchWith((value) => parse(decodeFromBinary(value))),
  stringifySearch: stringifySearchWith((value) =>
    encodeToBinary(stringify(value))
  ),
});
 
function decodeFromBinary(str: string): string {
  return decodeURIComponent(
    Array.prototype.map
      .call(atob(str), function (c) {
        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
      })
      .join("")
  );
}
 
function encodeToBinary(str: string): string {
  return btoa(
    encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
      return String.fromCharCode(parseInt(p1, 16));
    })
  );
}

이 구성으로 이전 객체를 검색 문자열로 변환하면 다음과 같이 나타납니다:

?page=1&sort=asc&filters=JTdCJUMyJUE4YXV0aG9yJUMyJUE4JUMyJUE4dGFubmVyJUMyJUE4JUMyJUE4bWluX3dvcmRzJUMyJUE4JUMyJUEyQ3UlN0Q%3D

Safe Binary Encoding/Decoding

브라우저에서 atobbtoa 함수는 비-UTF8 문자를 제대로 처리하지 못할 수 있습니다. 아래의 인코딩/디코딩 유틸리티를 사용하는 것을 권장합니다:

문자열을 이진 문자열로 인코딩하려면:

export function encodeToBinary(str: string): string {
  return btoa(
    encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
      return String.fromCharCode(parseInt(p1, 16));
    })
  );
}

이진 문자열을 문자열로 디코딩하려면:

export function decodeFromBinary(str: string): string {
  return decodeURIComponent(
    Array.prototype.map
      .call(atob(str), function (c) {
        return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
      })
      .join("")
  );
}