책 형태의 네비게이션 효과 - Part2 검색어 검색 기능 추가
ㆍProject Diary/React + Firebase (Snack ShoppingMall)
책 형태의 네비게이션에서 검색어를 입력하여 해당 페이지로 이동하는 기능을 추가하는 방법 기록
1. 검색 컴포넌트 만들기
먼저 검색 기능을 구현하는 SnackSearch 컴포넌트를 작성합니다
// 검색 컴포넌트 정의
const SnackSearch = ({ onSearch }) => {
const [searchValue, setSearchValue] = useState(""); // 검색어 상태
const handleInputChange = (e) => {
setSearchValue(e.target.value); // 검색어 상태 업데이트
};
const onClick = () => {
handleSearch(); // 검색 버튼 클릭 시 검색 함수 호출
};
const onKeyPress = (e) => {
if (e.key === "Enter") {
handleSearch(); // 엔터 키 입력 시 검색 함수 호출
}
};
const handleSearch = () => {
if (searchValue.length >= 1) {
onSearch(searchValue); // 검색어가 입력된 경우 부모 컴포넌트로 검색어 전달
setSearchValue(""); // 입력 필드 초기화
}
};
return (
<SnackSearchBlock>
<h2>과자 정보</h2>
<input
type="search"
placeholder="과자를 검색하세요"
value={searchValue}
onChange={handleInputChange}
onKeyPress={onKeyPress}
/>
<button type="button" onClick={onClick}>
검색
</button>
</SnackSearchBlock>
);
};
export default SnackSearch;
여기서 SnackSearch 컴포넌트는 검색어 입력을 받고, 엔터키를 누르거나 검색 버튼을 클릭했을 때 검색어를 부모 컴포넌트로 전달하는 역할을 합니다.
2. 검색 기능을 SnackList에 추가하기
이제 SnackList 컴포넌트에서 검색어를 받아 해당 페이지로 이동하는 기능을 추가합니다.
useEffect(() => {
if (searchKeyword && searchKeyword.length >= 1) {
// 1. 검색어가 입력되었는지 확인
const matchedPages = oddPagesData.filter((page) =>
page.title.includes(searchKeyword)
);
// 2. 검색어와 일치하는 페이지가 있는지 확인
if (matchedPages.length > 0) {
const matchedPageIndex = oddPagesData.indexOf(matchedPages[0]) * 2;
// 3. 현재 페이지 인덱스 업데이트
setCurrentPageIndex(matchedPageIndex);
// 4. 해당 페이지로 이동
setTimeout(() => {
pageFlipRef.current.pageFlip().flip(matchedPageIndex);
}, 500);
}
}
}, [searchKeyword]);
위 코드에서 각 부분을 자세히 설명하겠습니다.
검색어가 입력되었는지 확인
if (searchKeyword && searchKeyword.length >= 1) {
- 검색어가 비어있지 않고 길이가 1이상일 때만 코드를 실행함으로써 검색어가 입력되었는지 확인합니다.
검색어와 일치하는 페이지 찾기
const matchedPages = oddPagesData.filter((page) =>
page.title.includes(searchKeyword)
);
- oddPagesData 배열에서 각 페이지의 title 속성이 검색어를 포함하는지 필터링합니다. 일치하는 페이지들을 matchedPages 배열에 저장합니다.
- 여기서 filter 메소드는 oddPagesData 배열을 순회하면서 각 page 객체의 title 속성이 searchKeyword를 포함하는지를 검사합니다.
일치하는 페이지가 있는지 확인
if (matchedPages.length > 0) {
const matchedPageIndex = oddPagesData.indexOf(matchedPages[0]) * 2;
- 일치하는 페이지가 하나 이상 있는 경우, 첫 번째 일치하는 페이지의 인덱스를 찾아 matchedPageIndex에 저장합니다. 이 인덱스는 해당 페이지의 짝수 인덱스를 나타내기 위해 2를 곱합니다.
- oddPagesData.indexOf(matchedPages[0])는 일치하는 첫 번째 페이지의 인덱스를 반환합니다. 이 인덱스에 2를 곱하여 matchedPageIndex를 계산합니다.
- 짝수 인덱스를 사용하는 이유는 페이지가 홀수 페이지와 짝수 페이지로 구성되어 있기 때문입니다.
현재 페이지 인덱스 업데이트
setCurrentPageIndex(matchedPageIndex);
- 찾아낸 인덱스를 currentPageIndex 상태에 저장합니다.
해당 페이지로 이동
setTimeout(() => {
pageFlipRef.current.pageFlip().flip(matchedPageIndex);
}, 500);
- 0.5초 후에 PageFlip 컴포넌트의 flip 메소드를 호출하여 해당 페이지로 이동합니다.
- setTimeout을 사용하는 이유는 페이지 이동이 부드럽게 이루어지도록 하기 위함입니다.
- pageFlipRef.current.pageFlip().flip(matchedPageIndex)는 PageFlip 컴포넌트의 flip 메소드를 호출하여 지정한 인덱스의 페이지로 이동합니다.
3. 전체 컴포넌트 연결
마지막으로, SnackSearch와 SnackList 컴포넌트를 포함한 상위 컴포넌트를 만들어서 연결합니다.
SnackInfoView.js
import React, { useState } from "react";
import styled from "styled-components";
import SnackSearch from "@/components/snackInfo/SnackSearch";
import SnackList from "@/components/snackInfo/SnackList";
// 기본적인 스타일링과 컴포넌트 정의
const SnackInfoViewBlock = styled.div``;
// SnackInfoView 컴포넌트 정의
const SnackInfoView = () => {
const [searchKeyword, setSearchKeyword] = useState(""); // 검색어 상태
const handleSearch = (keyword) => {
setSearchKeyword(keyword); // 검색어 업데이트
};
return (
<SnackInfoViewBlock>
<SnackSearch onSearch={handleSearch} />
<SnackList searchKeyword={searchKeyword} />
</SnackInfoViewBlock>
);
};
export default SnackInfoView;
SnackInfoView 컴포넌트는 SnackSearch 컴포넌트에서 검색어를 입력받아 searchKeyword 상태를 업데이트합니다.
searchKeyword 상태가 변경되면 SnackList 컴포넌트에 전달하여 해당 페이지로 이동합니다.
이렇게 함으로써, 사용자는 검색어를 입력하여 책 형태의 네비게이션에서 원하는 페이지로 바로 이동할 수 있게 됩니다.