게시판에 들어오는 값들을 단어로 쪼개서 검색전용Board를 따로 만들고 그 단어가 몇 번 게시물에 있는지 게시물 번호를 저장해 놓은 뒤, 해당 단어로 검색이 들어오면 검색전용Board에 저장되어있는 Board의 값을 보여주는 형태로 보통 검색이 이루어진다.
토크나이징
: 토큰단위로 단어를 쪼개는 것
역인덱스 방식
: Data를 특정 키워드들로 구분지어, 해당하는 글들을 모아 저장하는 방식
이 방식을 쉽게 만들어 주는 도구가 Elastic Search
이 방식은 Disk에 저장되는 방식으로 컴퓨터가 꺼져도 저장이 유지되고 안전하지만 속도가 조금 떨어짐.
반면, Memory에 저장되는 방식은 Disk저장보다는 안정성이 떨어지지만 속도가 빠름
(많이 검색되는 것 위주로 메모리DB에 올려놓음)
Redis
: 메모리저장기반 방식
CPU / RAM ⇢ 변수, 빠름 / DISK ⇢ 파일, 느림
연이어 발생한 이벤트를 하나의 그룹으로 묶어 처리하는 방식으로 주로 그룹에서 마지막, 혹은 처음에 처리된 함수를 처리하는 방식으로 사용된다.
특정 시간 이내에 추가 입력이 없을 시, 마지막에 1회 실행
throttling:
연이어 발생한 이벤트에 대해 일정한 delay를 포함 시켜, 연속적으로 발생하는 이벤트는 무시하는 방식으로 사용된다.
ex) 스크롤 기능
특정 시간 이내에 추가 입력이 있어도 처음 1회만 실행
lodash : JS 유틸리티 라이브러리, 내장되어있는 유용한 함수가 많으므로 참고해서 사용하면 좋다!
npm에서 설치 가능
yarn add lodash
yarn add --dev @types/lodash
import { gql, useQuery } from "@apollo/client";
import { ChangeEvent, MouseEvent, useState } from "react";
import _ from "lodash";
import { v4 as uuidv4 } from "uuid";
const FETCH_BOARDS = gql`
query ($page: Int, $search: String) {
fetchBoards(page: $page, search: $search) {
_id
writer
title
contents
}
}
`;
export default function StaticRoutedPage() {
// const [search, setSearch] = useState("");
const [keyword, setKeyword] = useState("");
const { data, refetch } = useQuery(FETCH_BOARDS);
const onClickPage = (event: MouseEvent<HTMLSpanElement>) => {
// 검색에서 refetch할 때 사용한 search 검색어가 저장되어있는 상태이므로 추가로 search 포함하지 않아도 됨
void refetch({ page: Number(event.currentTarget.id) });
};
// const onClickSearch = () => {
// // search에 들어간 단어로 다시 리패치하는데, 검색을 요청할 때는 무조건 1페이지로 로드 되므로 1페이지로 명시해주어야함
// void refetch({ search, page: 1 });
// };
const getDebounce = _.debounce((value) => {
void refetch({ search: value, page: 1 });
setKeyword(value);
}, 500);
const onChangeSearch = (event: ChangeEvent<HTMLInputElement>) => {
getDebounce(event.currentTarget.value);
// debounce 직접 만들기
// setTimeout(() => {}, 1000);
};
// 더 안전한 시크릿 코드
const mySecretCode = uuidv4();
return (
<div>
검색어입력 : <input type="text" onChange={onChangeSearch} />{" "}
{/* <button onClick={onClickSearch}>검색하기</button> */}
{data?.fetchBoards.map((el) => (
<div key={el._id}>
<span style={{ margin: "10px" }}>
{el.title
.replaceAll(keyword, `${mySecretCode}${keyword}${mySecretCode}`)
.split(mySecretCode)
// .replaceAll(keyword, `@#$%${keyword}@#$%`)
// .split("@#$%")
.map((el) => (
<span
key={uuidv4()}
style={{ color: el === keyword ? "red" : "black" }}
>
{el}
</span>
))}
</span>
<span style={{ margin: "10px" }}>{el.contents}</span>
</div>
))}
{new Array(10).fill(1).map((_, index) => (
<span key={index + 1} id={String(index + 1)} onClick={onClickPage}>
{index + 1}
</span>
))}
</div>
);
}
쵝오