Skip to content

Commit 4b2fa93

Browse files
feat: implement webview streaming
we should useSyncExternalStore instead
1 parent 1ff36c4 commit 4b2fa93

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

src/webview/hooks/useSearch.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
import type { SgSearch } from '../postMessage'
22
import { childPort } from '../postMessage'
3-
import { useCallback, useMemo, useState } from 'react'
3+
import { useCallback, useMemo, useState, useRef } from 'react'
44
import { useDebounce } from 'react-use'
55

6+
type StreamHandler = (r: SgSearch[]) => void
7+
68
// id should not overflow, the MOD is large enough
79
// for most cases (unless there is buggy search)
810
const MOD = 1e9 + 7
911

1012
// maintain the latest search task id and callback
1113
let id = 0
12-
let currentResolve: (r: SgSearch[]) => void
14+
let currentResolve: (id: number) => void
1315
let currentReject = () => {}
16+
let currentHandler: StreamHandler
1417

15-
function postSearch(inputValue: string) {
18+
function postSearch(inputValue: string, onStream: StreamHandler) {
1619
id = (id + 1) % MOD
1720
childPort.postMessage('search', { id, inputValue })
1821
currentReject()
19-
return new Promise<SgSearch[]>((resolve, reject) => {
22+
currentHandler = onStream
23+
return new Promise<number>((resolve, reject) => {
2024
currentResolve = resolve
2125
currentReject = reject
2226
})
@@ -26,17 +30,16 @@ childPort.onMessage('searchResultStreaming', event => {
2630
if (event.id !== id) {
2731
return
2832
}
29-
currentResolve(event.searchResult)
30-
currentResolve = () => {}
31-
currentReject = () => {}
33+
currentHandler(event.searchResult)
3234
})
3335
childPort.onMessage('searchEnd', event => {
3436
if (event.id !== id) {
3537
return
3638
}
37-
currentResolve([])
39+
currentResolve(id)
3840
currentResolve = () => {}
3941
currentReject = () => {}
42+
currentHandler = () => {}
4043
})
4144

4245
function groupBy(matches: SgSearch[]) {
@@ -51,33 +54,35 @@ function groupBy(matches: SgSearch[]) {
5154
}
5255

5356
export const useSearchResult = (inputValue: string) => {
54-
const [searchResult, setResult] = useState<SgSearch[]>([])
57+
const resultRef = useRef<SgSearch[]>([])
5558
const [searching, setSearching] = useState(false)
5659
const [queryInFlight, setQuery] = useState(inputValue)
5760

5861
const refreshSearchResult = useCallback(() => {
5962
setSearching(true)
60-
postSearch(inputValue)
61-
.then(res => {
62-
setResult(res)
63+
resultRef.current = []
64+
postSearch(inputValue, ret => {
65+
resultRef.current.push(...ret)
66+
setQuery(inputValue + resultRef.current.length)
67+
})
68+
.then(() => {
6369
setSearching(false)
64-
setQuery(inputValue)
6570
})
6671
.catch(() => {
6772
// TODO: cancelled request, should send cancel to extension
6873
})
6974
}, [inputValue])
7075

7176
const groupedByFileSearchResult = useMemo(() => {
72-
return [...groupBy(searchResult).entries()]
73-
}, [searchResult])
77+
return [...groupBy(resultRef.current).entries()]
78+
}, [resultRef.current.length])
7479

7580
useDebounce(refreshSearchResult, 100, [inputValue])
7681

7782
return {
7883
queryInFlight,
7984
searching,
80-
searchResult,
85+
searchResult: resultRef.current,
8186
groupedByFileSearchResult,
8287
refreshSearchResult
8388
}

0 commit comments

Comments
 (0)