๐Ÿ” ๊ฒ€์ƒ‰ ํŽ˜์ด์ง€ ๋ฆฌํŒฉํ† ๋ง: Query String ํ™œ์šฉํ•˜๊ธฐ

Yeonnยท2025๋…„ 3์›” 7์ผ
0

๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

๋ชฉ๋ก ๋ณด๊ธฐ
3/10
post-thumbnail

๐Ÿ” search ํŽ˜์ด์ง€์˜ ์ƒํƒœ๊ด€๋ฆฌ ?

๊ฒ€์ƒ‰ ์ž์ฒด๋Š” /list, /map ํŽ˜์ด์ง€์—์„œ ์ด๋ฃจ์–ด์ง€๊ณ , ๊ฒ€์ƒ‰์„ ์œ„ํ•œ ์˜ต์…˜์„ ์„ ํƒํ•˜๋Š” /search ํŽ˜์ด์ง€

๊ทธ๋ž˜์„œ ์ฒ˜์Œ์—๋Š” /search ํŽ˜์ด์ง€์˜ URL์— ๊ฒ€์ƒ‰ ๊ด€๋ จ๋œ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์ด ๋ถ™๋Š” ๊ฒƒ์ด ์–ด์ƒ‰ํ•˜๋‹ค๊ณ  ๋А๊ปด์ ธ์„œ
์ด๋ฏธ ์‚ฌ์šฉ์ค‘์ด๋˜ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ zustand๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค !

โ—๏ธ ๋ฌธ์ œ ์ƒํ™ฉ

โœ”๏ธ ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์œ ์ง€ ๋ถˆ๊ฐ€
โœ”๏ธ URL ๊ณต์œ  ์‹œ ๊ฒ€์ƒ‰ ์ƒํƒœ ์ „๋‹ฌ ๋ถˆ๊ฐ€
โœ”๏ธ ๋’ค๋กœ ๊ฐ€๊ธฐ/์•ž์œผ๋กœ ๊ฐ€๊ธฐ ์‹œ ๊ฒ€์ƒ‰ ์ƒํƒœ ์œ ์ง€ ๋ถˆ๊ฐ€

๐Ÿ› ๏ธ Query String์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง ํ•˜๊ธฐ

๊ทธ๋ž˜์„œ ์ƒํƒœ๋กœ๋งŒ ๊ด€๋ฆฌํ•˜๋˜ ๊ฒ€์ƒ‰ ์ƒํƒœ๋ฅผ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง(Query String) ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.
useSearchParams๋ฅผ ํ™œ์šฉํ•˜์—ฌ URL๊ณผ ๊ฒ€์ƒ‰ ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•˜์—ฌ
๋’ค๋กœ ๊ฐ€๊ธฐ, ์ƒˆ๋กœ๊ณ ์นจ ์‹œ์—๋„ ๊ฒ€์ƒ‰ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ๊ฒ€์ƒ‰์–ด๋ฅผ ํฌํ•จํ•œ URL์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์„ ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

โœ… React์˜ Query String ๊ด€๋ จ ํฌ์ŠคํŒ…

  • updateQueryString.ts
export const updateQueryString = (
  paramsToUpdate: Record<string, string | null>
) => {
  // ํ˜„์žฌ URL์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ๊ฐ€์ ธ์™€ ์ƒˆ๋กœ์šด URLSearchParams ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
  const params = new URLSearchParams(window.location.search);

  // paramsToUpdate ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ key-value๋ฅผ ์—…๋ฐ์ดํŠธ
  Object.entries(paramsToUpdate).forEach(([key, value]) => {
    if (value !== null) {
      // key-value ์„ค์ •( ์ด๋ฏธ ์žˆ๋‹ค๋ฉด ๋ฎ์–ด์”€ )
      params.set(key, value);
    } else {
      // value ๊ฐ€ null ์ผ ๊ฒฝ์šฐ key ์‚ญ์ œ
      params.delete(key);
    }
  });

  // ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜
  const queryString = params.toString();
  // ์ƒˆ๋กœ์šด URL ์ƒ์„ฑ ( ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์ด ์—†์„ ๊ฒฝ์šฐ pathname๋งŒ ์œ ์ง€ )
  const newUrl = queryString
    ? `${window.location.pathname}?${queryString}`
    : window.location.pathname;

  // ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์Œ“์ง€ ์•Š์œผ๋ฉด์„œ URL ์—…๋ฐ์ดํŠธ
  window.history.replaceState(null, '', newUrl);
};
  • createApiUrl.ts
export const createApiUrl = (
  baseUrl: string,
  paramsList: { name: string; value?: string | number | null }[]
) => {
  // ์ƒˆ๋กœ์šด URLSearchParams ๊ฐ์ฒด ์ƒ์„ฑ
  const params = new URLSearchParams();

  // ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ paramsList๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ value ๊ฐ’์ด ์œ ํšจํ•œ ๊ฒฝ์šฐ name=value ํ˜•ํƒœ๋กœ ์ถ”๊ฐ€
  paramsList.forEach(({ name, value }) => {
    if (value) {
      params.set(name, `${value}`);
    } else {
      // value ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์—์„œ ํ‚ค ์‚ญ์ œ
      params.delete(name);
    }
  });

  // baseUrl์— ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฐ˜ํ™˜
  return `${baseUrl}?${params.toString()}`;
};
  • search.tsx
// ํ™œ์šฉํ•˜๊ธฐ
const closeSearch = () => {
  // ๋’ค๋กœ ๊ฐ€๊ธฐ
  // history.back() ์€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์„ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์–ด ์ง€์–‘ !
  router.back();
};

useEffect(() => {
  // ํ˜„์žฌ URL์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ๊ฐ€์ ธ์™€ ์ƒˆ๋กœ์šด URLSearchParams ๊ฐ์ฒด ๋ฐ˜ํ™˜
  const currentQuery = new URLSearchParams(window.location.search);
  // 'detail' ํŽ˜์ด์ง€๋Š” ๊ฒ€์ƒ‰์ด ์•ˆ๋˜๋ฏ€๋กœ 'origin' ์‚ญ์ œ
  // originPath state์˜ ๊ธฐ๋ณธ๊ฐ’์„ 'map'์œผ๋กœ ์„ค์ •ํ•ด ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์—์„œ URL๋กœ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜
  // detail ํŽ˜์ด์ง€์—์„œ ์ ‘๊ทผ ์‹œ ๋ฐ”๋กœ 'map' ํŽ˜์ด์ง€์—์„œ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.
  const origin = currentQuery.get('origin');
  if (origin && origin !== 'detail') {
    setOriginPath(origin);
  }
  currentQuery.delete('origin');

  const updatedQuery = currentQuery.toString();
  setQuery(updatedQuery);
}, [updateRegion]);

// ์„ ํƒ๋œ ๋ฒ„ํŠผ์ด ์žˆ์„ ๊ฒฝ์šฐ, ์ฟผ๋ฆฌ๊ฐ€ ์ƒ์„ฑ -> ๊ฒ€์ƒ‰ ํŽ˜์ด์ง€ ์ด์ „์˜ ํŽ˜์ด์ง€์—์„œ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ€์ง€๊ณ  ๊ฒ€์ƒ‰ํ•œ๋‹ค.
// ์ฟผ๋ฆฌ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๊ธฐ์กด ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐ€๋„๋ก ๊ตฌํ˜„
const handleSearch = async () => {
  try {
    router.push(`/${originPath}?${query || ''}`);
  } catch (error) {
    console.error(error);
  }
};

๐Ÿš€ ๋ฆฌํŒฉํ† ๋ง ๊ฒฐ๊ณผ: UX ๊ฐœ์„ 

  • ์ƒˆ๋กœ ๊ณ ์นจ ์‹œ ๊ฒ€์ƒ‰์–ด ์œ ์ง€
  • ๋’ค๋กœ ๊ฐ€๊ธฐ / ์•ž์œผ๋กœ ๊ฐ€๊ธฐ ๊ฒ€์ƒ‰ ์œ ์ง€
  • ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ URL๋กœ ๊ณต์œ  ๊ฐ€๋Šฅ
  • ์™ธ๋ถ€ ํŽ˜์ด์ง€์—์„œ URL๋กœ ์ ‘๊ทผ ์‹œ์—๋„ ์—๋Ÿฌ ์—†์ด ์ž‘๋™ ๊ฐ€๋Šฅ !

0๊ฐœ์˜ ๋Œ“๊ธ€