NextJs Search

권수혁·2024년 4월 17일

왜 URL 검색 매개 변수를 사용할까 ?

  1. Bookmarkable and Shareable URLs

  2. Server-Side Rendering and Initial Load

    • URL 파라미터를 서버에 직접 사용해서 초기 상태를 렌더링 할 수 있어 서버 렌더링을 보다 쉽게 처리할 수 있다.
  3. Analytics and Tracking

    • URL 내에 검색 질의 필터등을 가져서 추가적인 클라이언트 측 로직을 요구 하지 않을 수 있다.

검색기능 시 사용하는 NextJS hook

  • useSearchParams : 현재 URL의 변수들에 접근 할 수 있게 해줌
    ex) /dashboard/invoices?page=1&query=pending
    -> {page: '1', query: 'pending'}

  • usePathname : 현재 주소의 경로를 보여줌
    ex) /dashboard/invoices
    -> '/dashboard/invoices'

  • useRouter : 클라이언트 구성요소 내의 경로간 탐색을 프로그래밍적으로 가능하게 함
    ex)
    router.push(...)
    router.replace(...)
    router.refresh()
    router.back()
    router.forward()
    ...

검색 기능에 적용해보기

'use client';
 
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { useSearchParams, usePathname, useRouter } from 'next/navigation';
 
export default function Search() {
  const searchParams = useSearchParams();
  const pathname = usePathname();
  const { replace } = useRouter();
 
  function handleSearch(term: string) {
    const params = new URLSearchParams(searchParams);
    if (term) {
      params.set('query', term);
    } else {
      params.delete('query');
    }
    replace(`${pathname}?${params.toString()}`);
  }
  
  
  return (
  	<input
        className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500"
        placeholder={placeholder}
        onChange={(e) => {
          handleSearch(e.target.value);
        }}
      />
  )
}
  • 'hello world' 입력시 /dashboard/invoices?query=hello+world 이런 식으로 포멧팅해서 URL에 보여준다.
  • NextJs 의 클라이언트 네비게이션으로 페이지 새로고침 없이 업데이트 된다.

+ input defaultValue (vs Value)

<input
  className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10     text-sm outline-2 placeholder:text-gray-500"
  placeholder={placeholder}
  onChange={(e) => {
    handleSearch(e.target.value);
  }}
  defaultValue={searchParams.get('query')?.toString()}
/>	
  • defaultValue 는 입력 필드의 초기 상태를 정의 함.
  • URL 과 동기화위해서 사용한다.

(vs Value)

(controlled vs Uncontrolled)
value 속성을 사용시에는 controlled component 로 다룬다. (리액트가 상태를 관리하도록)
defaultValue 사용 시에는 uncontrolled component 로 다룬다. (state 를 사용하지 않을시)
DOM 자체가 현재 상태를 관리하도록 하는 방법.

  • 제어 컴포넌트
    장점 : 상태관리 일관성, 실시간 유효성 검사 포멧팅, 컴포넌트 재사용성 ..
    • 단점 : 보일러 플레이트 코드 , 코드양 많아짐, 코드 양 많아질시 리렌더링 많아짐
  • 비제어 컴포넌트
    - 장점 : 직접적으로 리렌더링을 유발하지 않기에 성능상 이점.
    • 단점 : 제한된 상태 관리.

searchParams

export default async function Page({
  searchParams,
}: {
  searchParams?: {
    query?: string;
    page?: string;
  };
}) {

  ...

}

useSearchParams() vs searchParams prop

-클라이언트 에서 작업하는지 서버 에서 작업하는지에 따라 다르다.

  • 클라이언트 에서 작업시에는 useSearchParams() 를 사용,,
  • 서버 에서 작업시에는 searchParams 를 사용,,

Debouncing

연속된 이벤트 처리를 효율적으로 관리하기 위한 기술. 성능 문제를 방지하고 불필요한 함수 호출을 줄일 수 있다.

특정 시간 동안 발생하는 이벤트중에 마지막 이벤트만을 처리하도록 함으로써 작동.

예시 사례

function handleSearch(term: string) {
  console.log(`Searching... ${term}`);
 
  const params = new URLSearchParams(searchParams);
  if (term) {
    params.set('query', term);
  } else {
    params.delete('query');
  }
  replace(`${pathname}?${params.toString()}`);
}

이런식으로 검색창을 만들 었는데 , 이렇게 하면 매 키입력마다 이벤트가 발생해서 db에서 쿼리를 실행한다.

Searching... E
Searching... Em
Searching... Emi
Searching... Emil

이런 문제를 방지하기 위해 사용해보도록 하자.

구현할 수도 있지만 , debounce 라이브러리 사용시,

  1. 설치
npm i use-debounce
  1. 적용
const handleSearch = useDebouncedCallback((term) => {
  console.log(`Searching... ${term}`);
 
  const params = new URLSearchParams(searchParams);
  if (term) {
    params.set('query', term);
  } else {
    params.delete('query');
  }
  replace(`${pathname}?${params.toString()}`);
}, 300);

-> debouncing 을 이용해서 데이터베이스로의 요청수를 줄일 수 있다 .

출처 : https://nextjs.org/

profile
개발공부하고 있습니다

0개의 댓글