웹 애플리케이션에서 검색 기능을 구현할 때, 검색어를 URL의 Query String(쿼리 스트링)을 통해 전달하는 경우가 많다. 예를 들어, localhost:3000/search?q=사과
와 같은 URL에서 ?q=사과
부분이 쿼리 스트링이다. 이렇게 전달되는 query string의 설정은 어떻게 할 수 있을까?
Query String은 URL경로의 끝에 ?
와 함께 전달되는 값으로, 페이지 경로에 직접 영향을 주지 않으면서 정보를 전달할 수 있는 방법이다. 그렇기 때문에 Next 프로젝트에서도 이 search 페이지가 쿼리스트링을 쓰는 페이지라고 해서 폴더 구조를 따로 변경해야 된다거나, 하지는 않아.
이 Query String은 검색어, 필터 조건 등과 같은 데이터를 클라이언트에서 서버로 쉽게 전달할 수 있는 방법으로 자주 사용된다.
예를 들어, localhost:3000/search?q=사과
라는 URL에서 q=사과
는 검색어를 나타내며, 사용자가 입력한 검색어를 서버나 클라이언트에서 처리할 수 있다. 이 검색어를 서버나 클라이언트에서 처리한다는 의미는, 이 검색어 값을 기반으로 검색 결과를 처리하거나 동작을 수행할 수 있다는 뜻이다.
클라이언트는 쿼리 스트링을 받아 해당 값에 따라 동적으로 화면을 업데이트하거나 필터링된 데이터를 표시할 수 있다.
예를 들어, useRouter
훅을 사용해 쿼리 스트링에서 검색어를 읽어와 그 검색어에 맞는 콘텐츠나 검색 결과를 클라이언트에서 처리할 수 있다.
서버로부터 받은 검색 결과 데이터를 화면에 렌더링하거나, 클라이언트 측에서 직접 데이터를 필터링할 수도 있다.
Next.js에서 쿼리 스트링을 사용하는 페이지는 특별한 폴더 구조나 설정이 필요하지 않다. 예를 들어, search
경로에서 쿼리 스트링을 사용한다고 해서 별도로 폴더 구조를 변경할 필요는 없다. 대신, Next.js는 useRouter라는 훅을 제공하여 쿼리 스트링 값을 간편하게 처리할 수 있다.
쿼리 스트링을 읽어오기 위해서는 useRouter
라는 훅을 사용한다. 이를 사용하기 위해서는 next/router
패키지로부터 useRouter를 불러와야 한다.
import { useRouter } from 'next/router';
export default function SearchPage() {
const router = useRouter();
return <h1>Search</h1>;
}
위 코드에서 useRouter
훅을 호출하여 router
라는 변수에 할당하면, 이 변수 안에 router
객체가 저장이 되고 이router
객체를 통해 페이지의 경로와 관련된 다양한 정보를 사용할 수 있다.
그리고 이 router
객체에는 우리에게 필요한 대부분의 routing
과 관련된 정보가 다 저장이 되어있다. 그렇기 때문에 console.log(router)
출력해 보면,
back
이나 ppush
처럼 페이지를 뒤로가기 하거나, 또는 다른 경로로 이동시키는 메서드가 들어있는 것도 볼 수 있고 그리고, 그 밑에 query
라고 해서 객체 형태로 우리가 전달한 querystring
인 q
의 값이 들어있는 걸 볼 수 있다.주의!! useRouter를 가져올 때,
next/router
에서 가져와야 한다.next/navigation
에서 가져오지 않도록 주의해야 하는데 이유는,next/navigation
은 Next.js의App Router
와 관련된 패키지이기 때문에 호환성 문제가 발생할 수 있다.
useRouter
로 반환된 router
객체에는 페이지의 경로와 관련된 모든 정보가 들어 있다. 그 중에서도 쿼리 스트링은 router.query
객체에 저장된다.
import { useRouter } from 'next/router';
export default function SearchPage() {
const router = useRouter();
const { q } = router.query; // 구조분해할당으로 쿼리 값을 가져옴
return <h1>Search Result: {q}</h1>;
}
router.query.q
는 ?q=사과
와 같은 쿼리 스트링의 값을 가져오는 방법이다. 이 값을 사용해 검색어를 처리하거나 결과를 렌더링할 수 있다.그리고 또 이때 쿼리 스트링을 사용하는 페이지에서 router객체가 console에 두 번 출력되는데, 이렇게 메세지가 두번이나 출력되는 이유는, 이 Next앱이 우리가 전달한 쿼리스트링을 읽는 과정중에 컴포넌트를 한번 더 렌더링 시키기 때문이다.
그렇기 때문에 첫번째로 출력된 쿼리스트링 메세지에는 아직 쿼리스트링을 읽어오지 못했기 때문에 query에 빈 객체가 출력(query:{}
)이 되지만, 두 번째로 출력된 메세지에는 우리가 전달한 쿼리스트링을 잘 읽어오고 있는 걸 확인할 수 있음.
따라서, 쿼리 값이 비어있을 때를 처리해주는 로직을 작성하는 것이 좋다.
import { useRouter } from 'next/router';
export default function SearchPage() {
const router = useRouter();
const { q } = router.query;
// q 값이 없으면 로딩 중이라는 메시지 출력
if (!q) {
return <h1>Loading...</h1>;
}
return <h1>Search Result: {q}</h1>;
}
localhost:3000/search?q=사과
로 접속했을 때, q
의 값을 화면에 렌더링한다. 만약 쿼리 스트링 값이 아직 받아지지 않은 경우 Loading...이라는 메시지를 먼저 출력하고, 쿼리 값이 정상적으로 전달되면 검색 결과를 보여준다.