- 使用 debouce 处理
- 使用 usememo 优化搜索逻辑
过滤器
钩子使用 .reduce() 按顺序将每个 filter 函数应用于数据,保持逻辑简洁和模块化:
return filters.reduce(
(acc, feature) => feature(acc, debouncedQuery),
dataArray
);支持不同的搜索
export function search(options) {
const { fields, matchType } = options;
return (data, query) => {
const trimmedQuery = String(query).trim().toLowerCase();
if (!trimmedQuery) return data;
return data.filter((item) => {
const fieldsArray = fields
? Array.isArray(fields)
? fields
: [fields]
: getAllKeys(item);
return fieldsArray.some((field) => {
const fieldValue = getFieldValue(item, field);
if (fieldValue == null) return false;
const stringValue = convertToString(fieldValue).toLowerCase();
switch (matchType) {
case "exact":
return stringValue === trimmedQuery;
case "startsWith":
return stringValue.startsWith(trimmedQuery);
case "endsWith":
return stringValue.endsWith(trimmedQuery);
case "contains":
return stringValue.includes(trimmedQuery);
default:
throw new Error(`Unsupported match type: ${matchType}`);
}
});
});
};
}支持模糊搜索
为了实现这一点,我们将使用一种模糊搜索技术来匹配相似的单词,即使它们的拼写不完全相同。我们将使用 n-gram 相似度算法来实现这一点,该算法将单词分成更小的片段 (n-gram) 并进行比较以查找匹配项。
export const nGramFuzzySearch = (value, query) => {
const n = 2; // Default to bigrams (two-character sequences)
const valueGrams = generateNGrams(value.toLowerCase(), n);
const queryGrams = generateNGrams(query.toLowerCase(), n);
const intersection = valueGrams.filter((gram) => queryGrams.includes(gram));
return intersection.length / Math.max(valueGrams.length, queryGrams.length);
};
const generateNGrams = (str, n) => {
const grams = [];
for (let i = 0; i <= str.length - n; i++) {
grams.push(str.slice(i, i + n));
}
return grams;
};