input박스에서 검색어를 치면 자동완성 기능을 만드려고 한다.
우리가 검색을 하려고 하는 기능은
1. 책검색
2. 사용자가 올린 태그 기반으로 컬렉션 검색
태그로 컬렉션을 검색하는 것은
태그가 별로 없기 때문에
글자를 칠때마다 요청을 보내는 것보다는 한번에 받아와서 프론트에서 처리하는게 낫다고 생각했다.
그래서 먼저 태그를 배열로 한번에 받은 다음에 Hint라는 라이브러리를 사용해서 구현했다.
이것은 다음 게시물에 담겠다.
그런데 책 검색 같은경우에는 책이 워낙 방대하다보니 한번에 받아오는 것은 불가능했다.
그래서 2글자 이상 쳤을때 디바운스를 이용하여 일정 시간동안 이벤트가 없으면 서버에 검색요청이 가도록 했다.
그리고 서버에서 받아온 값을 리덕스에 저장하고 리덕스에 있는 값을 밑에 띄웠다.
여기서 클릭을 하면 클릭한 값이 input박스의 value로 들어가도록 만들었고 바로 검색이 되도록 하고싶다.
여기서 같은 값이 나오기도 한다. 이게 보니까 체험판도 있고 무슨 한정판도 있고 그래서 저게 중복으로 나오는거다.
한가지 문제가 더 생겼다.
제목을 클릭하면 저렇게 태그가 같이 들어갈때도 있다.
text =p?.title.replace(/<(\/)?([a-zA-Z]*)(\s[a-zA-Z]*=[^>]*)?(\s)*(\/)?>/ig, "");
이 식을써서 정규식으로 태그를 없애줬다.
검색페이지
import React, { useEffect, useState, useRef, useCallback ,useMemo} from "react";
import styled from "styled-components";
import Color from "../../shared/Color";
import SearchIcon from "@material-ui/icons/Search";
import { useDispatch, useSelector } from "react-redux";
import { actionCreators as reviewActions } from "../../redux/modules/review";
import { actionCreators as bookActions} from "../../redux/modules/book";
import { actionCreators as searchActions } from "../../redux/modules/search";
import { Hint } from 'react-autocomplete-hint';
import SelectBookCard from "../../components/SelectBookCard";
import BookCard from "../../elements/BookCard";
const Search = (props)=>{
const dispatch = useDispatch();
const alltags = useSelector(state=> state.review.all_tags);
const search_book_list = useSelector(state=> state.search.search_book_list);
const [auto, setAutoComplete] = useState(false);
const search_book_title = useSelector(state=> state.search.search_book_title);
const text = useRef();
useEffect(()=>{
dispatch(reviewActions.getAllTagsSV());
return(
dispatch(searchActions.resetSelectedBook())
)
},[])
const searchBook = ()=>{
dispatch(searchActions.getSearchBooksSV(text.current.value))
}
let timer;
const search = ()=>{
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function() {
dispatch(searchActions.getSearchBooksSV(text.current.value))
setAutoComplete(true)
}, 1000);
}
return(
<Container>
<SearchBarBox >
<SearchIcon />
<Hint options={alltags} allowTabFill>
<input
style={{
width: "290px",
height: "48px",
color: `${Color.gray}`,
border: "none",
borderRadius: "12px",
backgroundColor: `${Color.mainColor}`,
padding: "0px 0px 0px 10px"
}}
placeholder="책이름, 저자명 등으로 검색해보세요"
onKeyPress ={(e)=>{
if(e.key === "Enter"){
searchBook()
setAutoComplete(false)
}
}}
onChange = {(e)=>{
if(text.current.value.length >=2){
search()
}
}}
ref={text}
/>
</Hint>
</SearchBarBox>
<Wrapper>
{/* 자동완성부분 */}
{
auto && <Autocomplete>
{
search_book_title?.map((p)=> {
return(<Title
key= {p?.isbn}
dangerouslySetInnerHTML={{__html: p?.title.split("(")[0]}}
onClick={()=>{
text.current.value =p?.title.replace(/<(\/)?([a-zA-Z]*)(\s[a-zA-Z]*=[^>]*)?(\s)*(\/)?>/ig, "").split("(")[0]
searchBook()
setAutoComplete(false)
}}
></Title>)
})
}
</Autocomplete>
}
{/* 책 나오는 부분 */}
<Grid>
{
!auto && search_book_title?.map((p,idx)=>{
return(<BookCard key={idx} {...p}></BookCard>)
})
}
</Grid>
</Wrapper>
</Container>
)
}
const Container = styled.div`
background: ${Color.mainColor};
width: 100%;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
`;
const SearchBarBox = styled.div`
width: 90%;
height: 50px;
border-bottom: 2px solid ${Color.gray};
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
position: relative;
background-color: ${Color.mainColor};
margin-top: 20px;
`;
const SearchBar = styled.input`
width: 100%;
height: 48px;
color: ${Color.gray};
border: none;
border-radius: 12px;
background-color: ${Color.mainColor};
:focus {
outline: none;
}
::placeholder {
color: ${Color.gray};
}
padding: 0px 0px 0px 10px;
`;
const Autocomplete = styled.div`
width: 100%;
height: 500px;
padding-left: 20px;
`;
const Title = styled.div`
`;
const Wrapper = styled.div`
background: ${Color.mainColor};
width: 100%;
min-height: 90vh;
height: 100%;
margin-top: 20px;
`;
const Grid = styled.div`
width: 100%;
height: 100%;
display: grid;
flex-direction: row;
grid-template-columns: 1fr 1fr 1fr;
`;
export default Search;
728x90
'WEB > REACT' 카테고리의 다른 글
[REACT] 리액트 메모에 대한 공부 링크 (0) | 2021.09.01 |
---|---|
[REACT] react-ga로 리액트 프로젝트에 google analytics 적용하기 (0) | 2021.08.27 |
[REACT] 리액트 컴포넌트에 scroll이벤트 사용하기/ debounce와 throttle (0) | 2021.08.23 |
[REACT] react transition group /리액트 라우터에 애니메이션 주기, 슬라이드 애니메이션, 특정 페이지에만 라우트 애니메이션 (0) | 2021.08.21 |
[REACT] useReducer로 상태 업데이트 컴포넌트 외부에서 사용하기 (0) | 2021.07.31 |