사용자가 입력한 검색어에 따라 다른 HTTP 요청을 보내고,
그에 맞는 검색 결과를 화면에 보여주기 위해 탠스택 쿼리를 사용해보자!!!
export default function FindEventSection() {
const searchElement = useRef(); // 입력 필드에 접근하기 위해 useRef 사용
const [searchTerm, setSearchTerm] = useState(); // 검색어 상태 관리, 초기값은 undefined
- searchTerm은 검색어를 상태로 관리하는 useState입니다.
- 초기값이 undefined이기 때문에, 초기에는 쿼리가 비활성화됩니다.
useQuery의 설정
const { data, isLoading, isError, error } = useQuery({
queryKey: ["events", { search: searchTerm }], // 검색어에 따라 쿼리 키가 변경
queryFn: ({ signal }) => fetchEvents({ signal, searchTerm }),
// fetchEvents 함수 호출
enabled: searchTerm !== undefined // searchTerm이 없으면 쿼리 비활성화
});
queryKey
["events", { search: searchTerm }]`으로 설정하여 검색어별로 서로 다른 쿼리 키를 만듭니다.
queryKey: ["events", { search: searchTerm }],
- "events": 기본 키로, 이벤트 데이터를 나타냅니다.
- { search: searchTerm }: 검색어를 포함하여 키를 구성함으로써 검색어마다 별도의 캐시를 생성합니다.
장점
동일한 검색어로 재요청할 때 캐시된 데이터를 재사용하여 불필요한 네트워크 요청을 방지합니다.
검색어가 변경될 때마다 새로운 데이터를 가져옵니다.
queryFn
이벤트를 검색하는 함수인 fetchEvents를 호출하며, searchTerm을 서버로 전달하여 필터링된 데이터를 가져옵니다.
queryFn: ({ signal }) => fetchEvents({ signal, searchTerm }),
실제로 데이터를 가져오는 비동기 함수입니다.
- signal: 요청을 취소할 수 있도록 제공되는 AbortSignal입니다. 컴포넌트가 언마운트되거나 요청이 필요 없게 되면 취소할 수 있습니다.
- fetchEvents 함수: 서버로부터 이벤트 데이터를 가져오는 사용자 정의 함수로, searchTerm을 인자로 받아 해당 검색어에 맞는 결과를 반환합니다.
- enabled: searchTerm이 undefined일 때 쿼리를 비활성화하여, 초기 로드 시 데이터 요청을 하지 않습니다. 이 값이 undefined가 아닌 경우 쿼리가 활성화됩니다
enabled
enabled: searchTerm !== undefined,
쿼리의 활성화 여부를 결정합니다.
- searchTerm이 undefined가 아니면 true가 되어 쿼리가 활성화되고, 데이터를 가져옵니다.
- searchTerm이 undefined이면 false가 되어 쿼리가 비활성화되고, 데이터를 가져오지 않습니다.
이유:
- 초기 로드 시: 사용자가 아직 검색어를 입력하지 않았으므로 불필요한 네트워크 요청을 방지합니다.
- 검색어 입력 후: searchTerm이 값(빈 문자열 포함)을 가지게 되며, 그에 따라 쿼리가 활성화되어 데이터를 가져옵니다.
특이점:
검색어가 빈 문자열 ""인 경우에도 쿼리가 활성화됩니다. 이 경우 서버에서 모든 이벤트를 가져오도록 구현
다시 : 왜 초기값을 undefined로 설정했나?
- 검색어가 처음부터 비어있을 때와 사용자가 검색어를 지워서 비어있을 때를 구분하기 위함입니다.
- 초기 로드 시: searchTerm이 undefined이며, 이때는 서버에 요청을 보내지 않고 초기 화면을 유지합니다.
- 검색 후 검색어를 지운 경우: searchTerm이 빈 문자열 ""이 되며, 이때는 모든 이벤트를 다시 가져와 표시합니다.
전체코드
import { useRef, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { fetchEvents } from "../../util/http";
import LoadingIndicator from "../UI/LoadingIndicator";
import ErrorBlock from "../UI/ErrorBlock";
import EventItem from "./EventItem";
export default function FindEventSection() {
const searchElement = useRef();
const [searchTerm, setSearchTerm] = useState();
const { data, isLoading, isError, error } = useQuery({
queryKey: ["events", { search: searchTerm }],
queryFn: ({signal}) => fetchEvents({signal,searchTerm}),
enabled:searchTerm !==undefined
});
function handleSubmit(event) {
event.preventDefault();
setSearchTerm(searchElement.current.value);
}
let content = <p>Please enter a search term and to find events.</p>;
if (isLoading) {
content = <LoadingIndicator />;
}
if (isError) {
content = (
<ErrorBlock
title="An error occurred"
message={error.info?.message || " events를 불러오는데 실패하였습니다. "}
/>
);
}
if (data) {
content = (
<ul className="events-list">
{data.map((event) => (
<li key={event.id}>
<EventItem event={event} />
</li>
))}
</ul>
);
}
return (
<section className="content-section" id="all-events-section">
<header>
<h2>Find your next event!</h2>
<form onSubmit={handleSubmit} id="search-form">
<input
type="search"
placeholder="Search events"
ref={searchElement}
/>
<button>Search</button>
</form>
</header>
{content}
</section>
);
}
동작 흐름
- 초기 상태: searchTerm이 undefined이므로 쿼리가 비활성화되고, 기본 안내 메시지가 표시됩니다.
- 검색어 입력: 사용자가 검색어를 입력하고 "Search" 버튼을 누르면, searchTerm 상태가 업데이트되고 쿼리가 활성화되어 서버로 데이터를 요청합니다.
- 로딩 중: 데이터를 가져오는 동안 isLoading이 true가 되어 로딩 스피너가 표시됩니다.
- 에러 처리: 데이터 요청 중 에러가 발생하면 isError가 true가 되어 에러 메시지가 표시됩니다.
- 데이터 렌더링: 데이터를 성공적으로 가져오면, 검색 결과가 리스트 형태로 화면에 표시됩니다.
- 검색어 제거: 검색어를 제거하면 다시 모든 이벤트가 표시됩니다.
isLoading과 isPending의 차이는???
1. isLoading
- isLoading은 쿼리가 처음 실행되거나, 쿼리 키가 변경되어 데이터를 새로 가져오는 동안 true가 됩니다.
- 쿼리가 비활성화(enabled: false)되면, isLoading은 true가 되지 않습니다. 이는 쿼리가 실제로 활성화되어 데이터를 요청하고 있을 때만 로딩 상태로 간주되기 때문입니다.사용자가 페이지를 처음 로드하거나 검색어를 입력하여 쿼리가 실행되기 시작할 때 로딩 스피너를 표시하고자 할 때 사용됩니다.
2. isPending
- isPending은 쿼리가 비활성화된 상태(enabled: false)에서 활성화되기를 기다리고 있는 경우를 포함하여, 쿼리 결과를 아직 받지 못했을 때 true가 됩니다.
- 쿼리가 비활성화되었지만, 활성화되어 데이터를 가져오기 전까지도 isPending은 true가 됩니다. 이는 쿼리가 데이터를 요청할 준비가 되었지만, 아직 요청이 발생하지 않았거나 결과를 받지 못했을 때도 대기 중으로 간주하는 것입니다.사용자가 입력을 통해 쿼리를 활성화하기를 기다리거나, 쿼리가 아직 결과를 반환하지 않았을 때 이러한 상태를 반영하고자 할 때 사용됩니다.
비활성화된 쿼리에서의 동작
isLoading은 쿼리가 비활성화된 경우 false가 됩니다.
-> 쿼리가 실제로 데이터 요청을 보내고 있는 상태만 반영합니다.
isPending은 쿼리가 비활성화된 상태에서도 true일 수 있습니다.
-> 쿼리가 활성화되기를 기다리고 있는 상태도 반영합니다.
이 차이 때문에, 일반적으로 사용자가 데이터를 로드하고 있음을 명확히 표시하려면 isLoading을 사용하고, 쿼리가 비활성화되어도 대기 중인 상태를 표현해야 한다면 isPending을 사용합니다.
'⚛️ React' 카테고리의 다른 글
Virtual DOM (1) | 2024.11.11 |
---|---|
React - StrictMode (0) | 2024.11.11 |
useRef 훅 : 효율적인 컴포넌트 관리 (0) | 2024.11.11 |
memo,useCallback 으로 불필요한 렌더링 줄이기 (0) | 2024.11.11 |
forwardRef와 useRef를 활용하여 modal 제어하기 (0) | 2024.11.11 |