SearchUser 컴포넌트는 Next.js를 사용자 검색 기능을 구현한 예입니다. 사용자 입력에 따라 검색 결과를 동적으로 불러오고, 검색 히스토리를 보여주는 기능을 포함하고 있습니다. 이 컴포넌트를 클린 아키텍처 원칙에 따라 구조화하고 평가하기 위해 각 부분을 분석하고 개선점을 확인해보겠습니다.
const SearchUser: React.FC = () => {
const [query, setQuery] = useState("");
const [searchResults, setSearchResults] = useState<APIUserSearchResponse["response"]["content"] | []>([]);
const { searchHistory, setSearchHistory } = useSearchStore();
const { toast } = useToast();
const debouncedQuery = useDebounce(query, 500);
const key = getKey();
useEffect(() => {
if (debouncedQuery === "") {
setSearchResults([]);
} else {
getSearches();
}
}, [debouncedQuery]);
const getSearches = async () => {
try {
const { response } = await searchUser(debouncedQuery);
setSearchResults(response.content);
setSearchHistory({ id: key, keyword: debouncedQuery });
} catch (error) {
toast(TOAST_MESSAGES.ERROR_PLEASE_RETRY);
}
};
const onChangeInputHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
};
return (
<div className="w-full flex flex-col items-center justify-between px-4 mt-3">
<SearchInput query={query} setQuery={setQuery} onChangeInputHandler={onChangeInputHandler} />
{searchResults.length ? (
<ul className="w-full mt-[16px]">
{searchResults.map((user) => (
<SearchUserList key={user.id} user={user} />
))}
</ul>
) : (
<ul className="w-full mt-[16px]">
{searchHistory.map((searchBox) => (
<SearchHistory key={searchBox.id} searchBox={searchBox} setSearchResults={setSearchResults} />
))}
</ul>
)}
</div>
);
};
export default SearchUser;
Domain Layer: 플랫폼/프레임워크와 독립적으로 구성
• Model : 문제와 관련된 실제 세계의 Object
• Repository: 모델에 접근 가능한 인터페이스 제공
• UseCase: 애플리케이션의 비즈니스 로직 포함
Presentation Layer: 사용자에게 화면으로 보여지는 레이어
• SearchInput: 사용자의 검색어 입력을 받습니다.
• SearchUserList: 검색 결과를 리스트 형태로 보여줍니다.
• SearchHistory: 이전 검색어를 기반으로 히스토리를 보여줍니다.
Data Layer: 애플리케이션이 데이터를 관리
• searchUser: API를 호출하여 사용자 검색 결과를 불러옵니다.
• useState: 검색어(query), 검색 결과(searchResults), 검색 히스토리(searchHistory)의 상태를 관리합니다.
• useSearchStore: 검색 히스토리를 전역 상태로 관리하는 커스텀 훅입니다.
의존성 분리와 관리
Presentation과 Data Layer 사이의 의존성을 명확히 분리합니다. 예를 들어, searchUser 같은 API 호출 로직은 별도의 서비스 레이어나 리포지토리 레이어에 위치시켜 컴포넌트에서는 단순히 호출만 합니다.
상태 관리의 단일 책임 원칙 적용
각 상태는 그와 관련된 로직만 처리합니다. 예를 들어, 검색어 상태 관리는 SearchInput 컴포넌트 내부에서 처리하고, 검색 결과 관리는 상위 레벨에서 처리하는 등의 구분을 명확히 합니다.
에러 처리 및 사용자 경험 향상
에러 처리 로직을 강화하여 사용자에게 보다 명확한 피드백을 제공합니다. 에러가 발생했을 때 사용자가 이해하기 쉽고 직관적인 메시지를 제공합니다.
테스트 용이성 확보
컴포넌트의 테스트를 용이하게 하기 위해 의존성 주입을 활용합니다. 예를 들어, API 호출 함수를 props으로 받게 함으로써 컴포넌트가 외부에 종속되지 않고 독립적으로 테스트 가능하게 합니다.
SearchUser 컴포넌트는 기능적으로 잘 구현되어 있으나, 클린 아키텍처 원칙을 적용하여 각 계층의 역할을 더 명확히 할 필요가 있다. 이를 통해 더 견고하고, 유지보수가 쉬우며, 테스트 가능한 코드 베이스를 만들 수 있겠다. 각 계층이 자신의 책임만을 수행하도록 구조를 개선해야겠다.