perf: optimize search

This commit is contained in:
skinmaker1345 2024-03-04 23:34:36 +09:00
parent 34a8ad2f24
commit ad90f8d699
2 changed files with 39 additions and 28 deletions

View File

@ -19,7 +19,7 @@ const Search: React.FC = () => {
const [recentSearch, setRecentSearch] = useState([]) const [recentSearch, setRecentSearch] = useState([])
const [data, setData] = useState<ResponseProps<ListAll>>(null) const [data, setData] = useState<ResponseProps<ListAll>>(null)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [abortControl, setAbortControl] = useState(new AbortController()) const abortController = useRef(null)
const [hidden, setHidden] = useState(true) const [hidden, setHidden] = useState(true)
useEffect(() => { useEffect(() => {
setQuery('') setQuery('')
@ -32,26 +32,37 @@ const Search: React.FC = () => {
} }
}, [router]) }, [router])
useOutsideClick(ref, () => setHidden(true)) useOutsideClick(ref, () => setHidden(true))
const SearchResults = async (value: string) => {
setData(null) useEffect(() => {
setQuery(value) if (query.length < 2) {
try { setData(null)
abortControl.abort() return
} catch (e) {
return null
} }
const controller = new AbortController() const timeout = setTimeout(async () => {
setAbortControl(controller) setData(null)
if (value.length > 1) setLoading(true) try {
const res = await Fetch<ListAll>(`/search/all?q=${encodeURIComponent(value)}`, { if (abortController.current) {
signal: controller.signal, abortController.current.abort()
}).catch((e) => { }
if (e.name !== 'AbortError') throw e } catch (e) {
else return return null
}) }
setData(res || {}) abortController.current = new AbortController()
setLoading(false) if (query.length > 1) setLoading(true)
} const res = await Fetch<ListAll>(`/search/all?q=${encodeURIComponent(query)}`, {
signal: abortController.current.signal,
}).catch((e) => {
if (e.name !== 'AbortError') throw e
else return
})
abortController.current = null
setData(res || {})
setLoading(false)
}, 1000)
return () => {
clearTimeout(timeout)
}
}, [query])
const onSubmit = () => { const onSubmit = () => {
if (query.length < 2) return if (query.length < 2) return
@ -93,7 +104,7 @@ const Search: React.FC = () => {
placeholder='검색...' placeholder='검색...'
value={query} value={query}
onChange={(e) => { onChange={(e) => {
SearchResults(e.target.value) setQuery(e.target.value)
}} }}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
@ -208,7 +219,7 @@ const Search: React.FC = () => {
))} ))}
</> </>
) )
) : query.length < 3 ? ( ) : query.length < 2 ? (
'최소 2글자 이상 입력해주세요.' '최소 2글자 이상 입력해주세요.'
) : ( ) : (
'검색어를 입력해주세요.' '검색어를 입력해주세요.'

View File

@ -301,8 +301,8 @@ async function getBotList(type: ListType, page = 1, query?: string): Promise<Lis
)[0][0]['count(*)'] )[0][0]['count(*)']
res = ( res = (
await knex.raw( await knex.raw(
'SELECT id, votes, MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) as relevance FROM bots WHERE `state` != "blocked" AND MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) ORDER BY relevance DESC, votes DESC LIMIT 16 OFFSET ?', 'SELECT id, votes, MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) as relevance FROM bots WHERE `state` != "blocked" AND MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) ORDER BY relevance DESC, votes DESC LIMIT 8 OFFSET ?',
[decodeURI(query) + '*', decodeURI(query) + '*', ((page ? Number(page) : 1) - 1) * 16] [decodeURI(query) + '*', decodeURI(query) + '*', ((page ? Number(page) : 1) - 1) * 8]
) )
)[0] )[0]
} else { } else {
@ -314,7 +314,7 @@ async function getBotList(type: ListType, page = 1, query?: string): Promise<Lis
type, type,
data: (await Promise.all(res.map(async (el) => await getBot(el.id)))).map((r) => ({ ...r })), data: (await Promise.all(res.map(async (el) => await getBot(el.id)))).map((r) => ({ ...r })),
currentPage: page, currentPage: page,
totalPage: Math.ceil(Number(count) / 16), totalPage: Math.ceil(Number(count) / 8),
} }
} }
@ -402,12 +402,12 @@ async function getServerList(type: ListType, page = 1, query?: string): Promise<
)[0][0]['count(*)'] )[0][0]['count(*)']
res = ( res = (
await knex.raw( await knex.raw(
'SELECT id, votes, MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) as relevance FROM servers WHERE `state` != "blocked" AND last_updated >= ? AND MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) ORDER BY relevance DESC, votes DESC LIMIT 16 OFFSET ?', 'SELECT id, votes, MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) as relevance FROM servers WHERE `state` != "blocked" AND last_updated >= ? AND MATCH(`name`, `intro`, `desc`) AGAINST(? in boolean mode) ORDER BY relevance DESC, votes DESC LIMIT 8 OFFSET ?',
[ [
decodeURI(query) + '*', decodeURI(query) + '*',
new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
decodeURI(query) + '*', decodeURI(query) + '*',
((page ? Number(page) : 1) - 1) * 16, ((page ? Number(page) : 1) - 1) * 8,
] ]
) )
)[0] )[0]
@ -419,7 +419,7 @@ async function getServerList(type: ListType, page = 1, query?: string): Promise<
type, type,
data: (await Promise.all(res.map(async (el) => await getServer(el.id)))).map((r) => ({ ...r })), data: (await Promise.all(res.map(async (el) => await getServer(el.id)))).map((r) => ({ ...r })),
currentPage: page, currentPage: page,
totalPage: Math.ceil(Number(count) / 16), totalPage: Math.ceil(Number(count) / 8),
} }
} }