간단한 검색 기능을 통해 디바운싱과 쓰로틀링에 대하여 알아보도록 했다.
검색어 입력하는 인풋과 검색하기 버튼을 만들고 검색어를 저장해야하니까 onChange 함수를 만들어 준다.
++검색어가 저장될 state도 만들어줌
const [search, setSearch] = useState("");
const onChangeSearch = (event) => {
setSearch(event.target.value); // 검색어
};
검색하기 버튼을 눌렀을 때 실행되는 함수를 만듬. onClickSearch
버튼을 눌렀을 때 refetch 하는데 검색하기 눌렀을때의 variables는 search가 들어가야한다.
search는 스테이츠에 저장되어있는 값을 넣어준다.
++search 에 해당하는 글들의 1페이지 2페이지 3페이지 가 나올텐데 그것도 생각해봐야한다.
→ 그 검색결과에 몇페이지를 보여줄 것인지 page가 붙어야한다 (variables에), 일반적으로 1페이지가 나오는 것이 일반적인 생각이니까 1페이지를 넣어보자.
+search 도 fetch해주어야 하니 fetchBoard 수정.
한줄요약: 검색은 refetch 이다!
검색하기 버튼을 빼버리고 검색어 입력부분으로만 검색
원리 : 클릭해서 refetch 했던 것을 변경할때마다 refetch 하면 되는 것이다!
// const [search, setSearch] = useState("");
const onChangeSearch = (event: ChangeEvent<HTMLInputElement>) => {
// setSearch(event.target.value);
refetch({ search: event.target.value, page: 1 });
};
굳이 state
에 저장해서 refetch
하는 것이 아닌 바로 event.target.value
로 refetch 시켜버리는 것
→ 굉장히 심플해졌다.
근데 여기에는 한가지 문제가 있다. Network 쪽을 한번 보자.
debouncing
(디바운싱) 이라고 한다 , 특정시간을 기준으로 해당시간내에 요청된 내용들은 무시!디바운싱을 하기 위해 Lodash
라는 라이브러리를 사용했다.
Lodash는 자바스크립트의 유틸리티 라이브러리이다.
내장되어 있는 유용한 함수가 많기 때문에 자주사용!
Lodash의 많은 기능 중 디바운싱 내용에 대해 알아보자!
먼저 Lodash를 사용하기 위해서는 설치를 해야 한다.
yarn add lodash
yarn add -D @types/lodash // 타입
이제 refetch를 할때마다 요청을 보내는것이 아닌 디바운싱을 하는 것이다.
// 사용법은 setTimeout이랑 비슷하다
const getDebounce = _.debounce((mydata) => {
refetch({ search: mydata, page: 1 });
// 1초 딜레이 후에 실행되야 하는것은 refetch 이기 때문에 위치를 디바운싱 안으로 이동! (onChage에서)
}, 1000);
const onChangeSearch = (event: ChangeEvent<HTMLInputElement>) => {
**getDebounce(event.target.value);**
// 체인지 할때마다 디바운싱이 실행되는데 매번 실행되는 것이 아닌 1초 기다렸다가 실행이 되는 것.
// event.target.value 의 위치도 조심, 디바운스 안에 있는 것이 아님.
};
실제 실무에서는 1초는 너무 길어서 0.2초 단위로 넣어서 사용한다. 200
먼저 실행하고 특정시간동안 재실행안하고 기다리는 것! 디바운싱과 다른부분.
쓰로틀링
이란, 연이어 발생한 이벤트에 대해 일정한 delay
를 포함 시켜, 연속적으로 발생하는 이벤트는 무시하는 방식으로 사용됨
즉, 지정한 delay
동안 호출된 함수는 무시, 쓰로틀링이 사용되는 대표적 예제는 스크롤 기능
이 있습니다
스크롤 이벤트를 걸어두면 스크롤을 내릴때 엄청나게 많은 스크롤 이벤트가 요청된다. 그때 쓰는 것이 쓰로틀링.
검색어 입력에 들어간 단어를 빨간색으로 표시해주고 싶다 → 방법?
import { useQuery, gql } from "@apollo/client";
import styled from "@emotion/styled";
const FETCH_BOARDS = gql`
query fetchBoards($page: Int) {
fetchBoards(page: $page) {
_id
writer
title
contents
}
}
`;
const MyRow = styled.div`
display: flex;
`;
const MyColumn = styled.div`
width: 25%;
`;
export default function MapBoardPage() {
const { data, refetch } = useQuery(FETCH_BOARDS);
const onClickPage = (event) => {
refetch({ page: Number(event.target.id) });
};
return (
<div>
{data?.fetchBoards.map((el: any) => (
<MyRow key={el._id}>
<MyColumn>{el.writer}</MyColumn>
<MyColumn>{el.title}</MyColumn>
</MyRow>
))}
{new Array(10).fill(1).map((_, index) => (
<span key={index + 1} id={String(index + 1)} onClick={onClickPage}>
{index + 1}
</span>
))}
</div>
);
}
const [keyword, setKeyword] = useState("");
{el.title
.replaceAll(keyword, `#$%${keyword}#$%`)
.split("#$%")
.map((el) => (
<Word key={uuidv4()} isMatched={keyword === el}>
{el}
</Word>
))}
// 이모션
const Word = styled.span`
color: ${(props: IProps) => (props.isMatched ? "red" : "black")};
`;
state와 타이틀 부분에 수정.
yarn add uuid
, yarn add --dev @types/uuid
refetch 할때 setKeyword 에 저장하고 그것을 빨간색으로 바꿔준다.
철수를 기준으로 쪼개면 3덩어리로 쪼개지게 되는 것. (split
)
그리고 map으로 꾸미게 되면 각각이 화면에 그려지고 그렬질때 keyword와 같다면 isMatched
가 true로 되는 것이다!
replaceALL
= 키워드를 변경시켜줌. 변경시켜준 값을 기준으로 split으로 짤라버림.
이모션
const **Word** = styled.span`
**color: ${(props: any) => (props.isMatched ? "red" : "black")};**
`;