๊ฒ์ ์์ฒด๋ /list
, /map
ํ์ด์ง์์ ์ด๋ฃจ์ด์ง๊ณ , ๊ฒ์์ ์ํ ์ต์
์ ์ ํํ๋ /search
ํ์ด์ง
๊ทธ๋์ ์ฒ์์๋ /search
ํ์ด์ง์ URL
์ ๊ฒ์ ๊ด๋ จ๋ ์ฟผ๋ฆฌ์คํธ๋ง์ด ๋ถ๋ ๊ฒ์ด ์ด์ํ๋ค๊ณ ๋๊ปด์ ธ์
์ด๋ฏธ ์ฌ์ฉ์ค์ด๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ zustand
๋ก ๊ด๋ฆฌํ๋ ๋ฐฉํฅ์ผ๋ก ๊ตฌํํ์๋ค.
๊ทธ๋ฐ๋ฐ ๋ฌธ์ ๊ฐ ์์๋ค !
โ๏ธ ์๋ก๊ณ ์นจ ์ ๊ฒ์ ๊ฒฐ๊ณผ ์ ์ง ๋ถ๊ฐ
โ๏ธ URL ๊ณต์ ์ ๊ฒ์ ์ํ ์ ๋ฌ ๋ถ๊ฐ
โ๏ธ ๋ค๋ก ๊ฐ๊ธฐ/์์ผ๋ก ๊ฐ๊ธฐ ์ ๊ฒ์ ์ํ ์ ์ง ๋ถ๊ฐ
Query String
์ผ๋ก ๋ฆฌํฉํ ๋ง ํ๊ธฐ๊ทธ๋์ ์ํ๋ก๋ง ๊ด๋ฆฌํ๋ ๊ฒ์ ์ํ๋ฅผ ์ฟผ๋ฆฌ ์คํธ๋ง(Query String) ๊ธฐ๋ฐ์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค.
useSearchParams
๋ฅผ ํ์ฉํ์ฌ URL๊ณผ ๊ฒ์ ์ํ๋ฅผ ๋๊ธฐํํ์ฌ
๋ค๋ก ๊ฐ๊ธฐ, ์๋ก๊ณ ์นจ ์์๋ ๊ฒ์ ์ํ๋ฅผ ์ ์งํ๊ณ ๊ฒ์์ด๋ฅผ ํฌํจํ URL์ ๊ณต์ ํ ์ ์๋๋ก ๊ฐ์ ํ๊ธฐ๋ก ํ๋ค.
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);
}
};
- ์๋ก ๊ณ ์นจ ์ ๊ฒ์์ด ์ ์ง
- ๋ค๋ก ๊ฐ๊ธฐ / ์์ผ๋ก ๊ฐ๊ธฐ ๊ฒ์ ์ ์ง
- ๊ฒ์ ๊ฒฐ๊ณผ URL๋ก ๊ณต์ ๊ฐ๋ฅ
- ์ธ๋ถ ํ์ด์ง์์ URL๋ก ์ ๊ทผ ์์๋ ์๋ฌ ์์ด ์๋ ๊ฐ๋ฅ !