Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 42 additions & 23 deletions src/utils/usedataList.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,63 @@
import * as JsSearch from "js-search";
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
const useDataList = (
data,
setSearchQuery,
searchQuery,
paramsIndex,
paramSearch
paramSearch,
) => {
const [dataList, setDataList] = useState(data);
const [search, setSearch] = useState([]);
const [searchResults, setSearchResults] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const queryResults = searchQuery ? searchResults : dataList;
useEffect(() => {
rebuildIndex();
}, [dataList]);

// The TF-IDF index is the expensive part of a search (it walks and
// tokenizes every document up front) - built lazily on the first real
// keystroke instead of eagerly on mount, since most renders of this hook
// (embedded previews, limited-count sections, visitors who never search)
// never need it at all. Invalidated whenever the underlying dataset
// changes so a stale index is never served.
const searchIndexRef = useRef(null);

useEffect(() => {
rebuildIndex();
}, []);
searchIndexRef.current = null;
// An active query's results were built from the old dataList - recompute
// them against the new one immediately instead of waiting for the next
// keystroke, otherwise queryResults keeps showing stale matches.
if (searchQuery) {
setSearchResults(getSearchIndex().search(searchQuery));
} else {
setSearchResults([]);
}
}, [dataList]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const rebuildIndex = () => {
const dataToSearch = new JsSearch.Search(paramSearch);
dataToSearch.indexStrategy = new JsSearch.PrefixIndexStrategy();
dataToSearch.sanitizer = new JsSearch.LowerCaseSanitizer();
dataToSearch.searchIndex = new JsSearch.TfIdfSearchIndex(paramSearch);
dataToSearch.addIndex(paramsIndex);
dataToSearch.addIndex("body");
dataToSearch.addDocuments(dataList);
setSearch(dataToSearch);
setIsLoading(false);
const getSearchIndex = () => {
if (!searchIndexRef.current) {
const dataToSearch = new JsSearch.Search(paramSearch);
dataToSearch.indexStrategy = new JsSearch.PrefixIndexStrategy();
dataToSearch.sanitizer = new JsSearch.LowerCaseSanitizer();
dataToSearch.searchIndex = new JsSearch.TfIdfSearchIndex(paramSearch);
dataToSearch.addIndex(paramsIndex);
dataToSearch.addIndex("body");
dataToSearch.addDocuments(dataList);
searchIndexRef.current = dataToSearch;
}
return searchIndexRef.current;
};

const searchData = (e) => {
const queryResult = search.search(e.target.value);
setSearchQuery(e.target.value.trim());
setSearchResults(queryResult);
const trimmedQuery = e.target.value.trim();
setSearchQuery(trimmedQuery);
// A blank query has nothing to search - skip it so an empty keystroke
// (or clearing the field) never forces the lazy index to build.
if (!trimmedQuery) {
setSearchResults([]);
return;
}
setSearchResults(getSearchIndex().search(trimmedQuery));
};

return { queryResults, searchData, setDataList,dataList };
return { queryResults, searchData, setDataList, dataList };
};

export default useDataList;