React中Fuse.js搜索为什么总是返回空数组?

司马梦媛 阅读 20

在做一个带搜索功能的React组件时,用Fuse.js处理模糊搜索,但输入内容后结果一直是空数组…

代码是这样写的,初始化了Fuse实例,数据格式也检查过了没问题:

import Fuse from 'fuse.js';

function Search({ items }) {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    const fuse = new Fuse(items, {
      keys: ['name', 'description']
    });
    const res = fuse.search(query);
    setResults(res);
  }, [query]);

  return (
    <input onChange={e => setQuery(e.target.value)} />
    {results.map(item => (
      <div key={item.item.id}>{item.item.name}</div>
    ))}
  );
}

输入测试数据时完全匹配的条目却搜不到,控制台也没报错,这是哪里出问题了?

我来解答 赞 12 收藏
二维码
手机扫码查看
2 条解答
Top丶紫瑶
这个问题挺常见的,主要是你在初始化Fuse.js和使用它的时候,有几处需要注意的地方。我分几步来帮你解决。

---

### 第一步:检查query的初始值
在你的代码里,query一开始是空字符串('')。当query为空时,fuse.search(query)会返回一个空数组,因为Fuse.js默认不会返回所有数据。
你可以通过设置 Fuse 的选项来改变这种行为,稍后再讲。

---

### 第二步:理解useEffect的触发时机
你的useEffect依赖了query,所以每次query变化都会重新创建一个Fuse实例。这其实是个性能问题,虽然不影响功能,但没必要每次都重新创建。我们可以优化一下,把Fuse实例提取到组件外或者用useRef缓存。

---

### 第三步:正确处理搜索逻辑
你现在的逻辑是直接用fuse.search(query)的结果更新results,但这里有一个小坑:
query为空时,Fuse.js不会返回任何结果。如果你希望在这种情况下显示所有的items,需要手动处理这种情况。

---

### 第四步:完整的解决方案代码
下面是修正后的代码,注释解释了每一步:

import React, { useState, useEffect, useRef } from 'react';
import Fuse from 'fuse.js';

function Search({ items }) {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);

// 使用 useRef 缓存 Fuse 实例,避免每次重新创建
const fuseRef = useRef(
new Fuse(items, {
keys: ['name', 'description'], // 指定要搜索的字段
threshold: 0.3, // 设置模糊匹配的阈值,越高越宽松
includeMatches: true, // 如果需要返回匹配信息,可以开启
})
);

useEffect(() => {
if (query === '') {
// 当 query 为空时,直接返回所有数据
setResults(items);
} else {
// 否则执行 Fuse 搜索
const res = fuseRef.current.search(query);
setResults(res.map(item => item.item)); // 注意:Fuse 返回的结果需要提取 item 属性
}
}, [query, items]);

return (
<div>
<input
type="text"
placeholder="Search..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>

<ul>
{results.length > 0 ? (
results.map((item) => (
<li key={item.id}>{item.name}</li>
))
) : (
<li>No results found</li>
)}
</ul>
</div>
);
}

export default Search;


---

### 第五步:解释改动的地方
1. **Fuse实例缓存**
我用了useRef来缓存Fuse实例,这样只有在组件首次加载时才会创建一次,避免不必要的性能开销。

2. **处理空查询的情况**
query为空时,直接返回所有的items。这是为了让用户体验更好,而不是让用户看到空列表。

3. **提取item属性**
fuse.search()返回的结果是一个对象数组,每个对象包含item和其他匹配信息。你需要提取出item部分才能正常渲染。

4. **增加模糊匹配的阈值**
threshold参数控制模糊匹配的严格程度,默认值是0(完全匹配)。我把它改成了0.3,这样可以让搜索更宽松一些。

---

### 第六步:测试和调试
记得用一些示例数据来测试这个组件,比如:

const data = [
{ id: 1, name: 'Apple', description: 'A fruit' },
{ id: 2, name: 'Banana', description: 'Another fruit' },
{ id: 3, name: 'Carrot', description: 'A vegetable' },
];

// 在 App 或其他地方使用
&lt;Search items={data} /&gt;


试着输入不同的关键词,看看结果是否符合预期。

---

如果你还有其他疑问,随时问!开发这些东西有时候确实有点绕,耐心调试就好~
点赞 6
2026-02-02 12:07
Des.子晨
问题出在 useEffect 里,你每次更新 query 都会重新创建一个 Fuse 实例。这样会导致性能问题,而且如果 items 没有正确更新,Fuse.js 搜索的结果肯定不对。

直接用 useMemo 把 Fuse 实例缓存起来,只在 items 变化时重新创建:

import Fuse from 'fuse.js';
import { useState, useEffect, useMemo } from 'react';

function Search({ items }) {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);

// 缓存 Fuse 实例
const fuse = useMemo(() => {
return new Fuse(items, {
keys: ['name', 'description']
});
}, [items]);

useEffect(() => {
if (query.trim() === '') {
setResults([]);
} else {
const res = fuse.search(query);
setResults(res);
}
}, [query, fuse]);

return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
{results.map((item) => (
<div key={item.item.id}>{item.item.name}</div>
))}
</div>
);
}


这样写就对了。记住,不要在 useEffect 里频繁创建大对象,用 useMemo 缓存一下能省不少事。
点赞 12
2026-01-28 19:13