사이드프로젝트에서 채팅룸에 현재 참여하고 있지 않은 유저들을 닉네임으로 검색한 후 초대하는 기능을 구현하였습니다.
검색된 유저들을 불러오는건 React-query의 useQuery를 사용하여 데이터를 fetching 하였습니다.
import { getSearchedUserList } from '@/service/chatRoom';
import { useQuery } from '@tanstack/react-query';
export default function useGetSearchedUserList(
roomId: string,
nickname: string,
) {
const { data, isLoading } = useQuery({
queryKey: ['searchedUserList', nickname],
queryFn: () => getSearchedUserList(roomId, nickname),
});
return { data, isLoading };
}
채팅방번호와, 검색한 닉네임을 인자로 넘겨주었고 nickname에 따라 API 콜을 보내도록 설계하였습니다.
문제점
처음엔 단순하게 생각하였기 때문에 데이터만 불러오면 쉽겠네~라고 생각하였습니다만 input에 nickname 상태가 바뀔 때마다 계속 API 요청이 지속되는 상황이 발생하였습니다.
문제를 해결하기 이전에...
문제를 해결하기전에 유저플로우에 대해 생각을 해보았고 닉네임을 통한 유저검색이 어떨 때 이루어져야 하는지 먼저 정의를 하였습니다.
- input 태그안에 있는 돋보기아이콘을 유저가 클릭할 때 검색요청을 보낸다.
- 유저가 검색어를 입력한 후 Enter를 눌렀을때 요청을 보낸다.
크게 이 두가지상황을 먼저 정의해 놓고 어떻게 구현하면 좋을지 생각했습니다.
해결! enabled 옵션과 refetch함수를 활용하자.
import { getSearchedUserList } from '@/service/chatRoom';
import { useQuery } from '@tanstack/react-query';
export default function useGetSearchedUserList(
roomId: string,
nickname: string,
) {
const { data, isLoading, refetch } = useQuery({
queryKey: ['searchedUserList', nickname],
queryFn: () => getSearchedUserList(roomId, nickname),
enabled: false,
});
return { data, isLoading, refetch };
}
enabled 옵션이란 무엇일까요? enabled는 useQuery의 동작을 제한합니다. false 라면 데이터를 fetching 하지 않고 true 일 때 데이터를 fetching 해옵니다.
enabled를 false로 설정함으로써 데이터를 가져오지않도록 막았습니다.
const { data: searchedList, refetch } = useGetSearchedUserList(
roomId,
nickname,
);
const fetchSearchedUserList = () => {
if (nickname.length === 0) return;
refetch();
};
<SearchInput
placeholder="추가할 인원의 아이디나 닉네임을 검색해보세요"
value={nickname}
onChangeValue={onChangeNickname}
resetValue={resetValue}
onClickSearchIcon={fetchSearchedUserList}
onPressEnter={fetchSearchedUserList}
/>
이후 refetch를 트리거하는 함수를 만들어주었고 해당 함수를 사용하는 곳에 적절히 적용시켜 주었습니다.
import { ChangeEvent } from 'react';
import SearchIcon from '@/public/search.svg';
import InputDeleteIcon from '@/public/input-delete.svg';
interface SearchInputType {
value: string;
resetValue: () => void;
onChangeValue: (e: ChangeEvent<HTMLInputElement>) => void;
placeholder: string;
className?: string;
onClickSearchIcon?: () => void;
onPressEnter?: () => void;
}
export default function SearchInput({
value,
resetValue,
onChangeValue,
placeholder,
className,
onClickSearchIcon,
onPressEnter,
}: SearchInputType) {
return (
<div className="relative w-full">
<input
type="text"
value={value}
onChange={onChangeValue}
className={`border border-grey-600 block rounded-[10px] px-5 py-4 pr-20 w-full ${className}`}
placeholder={placeholder}
onKeyUp={(event) => {
if (event.key === 'Enter') {
onPressEnter?.();
}
}}
/>
<div className="absolute inset-y-0 top-0 flex gap-2 right-4">
{value && (
<button type="button" onClick={resetValue}>
<InputDeleteIcon className="w-5 h-5 " />
</button>
)}
<button type="button" className="" onClick={onClickSearchIcon}>
<SearchIcon className="w-6 h-6" />
</button>
</div>
</div>
);
}
SearchInput 컴포넌트는 해당 유저검색모달에서 사용되지만 다른 곳에서도 사용되며 돋보기아이콘을 클릭했을 때 이벤트, 유저가 Enter를 입력했을 때 이벤트를 각각 설정하여 props로 내려 설정해 줄 수 있도록 설계를 해보았습니다.
수정완료!
'React' 카테고리의 다른 글
React Developer Tools를 통한 웹 최적화 진행 해보기 (0) | 2023.11.08 |
---|---|
React createPortal을 사용하여 Modal 구현 (0) | 2023.10.10 |
React- 재사용성과 확장성을 높이는 리액트 컴포넌트 설계 하기 (1) | 2023.09.25 |
React - 리액트 해시태그 구현 (0) | 2023.09.23 |
리액트 라이브러리없이 달력(Calender) 구현 with "date-fns" (0) | 2023.09.12 |