项目 49(共 100 个)- 使用自动完成功能进行搜索
嘿!我的任务是截止 3 月 31 日,完成 100 个 React.js 项目。请关注我的 dev.to 个人资料或推特获取最新动态,如有任何问题,请随时联系我。感谢您的支持!
今天我想在 React 中创建一个自动完成组件,因为我之前从未在 React 中实现过搜索功能,更不用说自动完成功能了。我其实很好奇其他人是如何从零开始实现这个功能的,因为使用星球大战 API 来实现这个功能相当简单。他们有自己的搜索功能,返回一个 JSON 结果数组,而且任何搜索返回的星球大战角色数量必然很少。如果你的数据库有 10 万个可能的结果怎么办?我想大多数数据库的结果数量都可以设置一个数字限制。
对于基础搜索组件,我改编了这篇 Dev.to 博客文章,将其变成了一个功能组件。我没有使用他们的 API,而是决定使用一个开放的星球大战角色搜索 API,它不需要注册,也不需要暴露我的邮箱地址。
该网站的结构很简单。它使用一个App
组件和一个Search
组件,重要的逻辑都发生在这里。它使用了三个状态query
,searchResults
并且selectedCharacter
它们在初始化时都设置为空:
const [query,setQuery] = useState('');
const [searchResults,setSearchResults] = useState([]);
const [selectedCharacter,setSelectedCharacter] = useState(null);
在返回语句中,我们为搜索功能创建一个带有文本输入的表单:
return (
<form className='search-form-container'>
<input
placeholder='Search for...'
onChange={handleInputChange}
value={query}
/>
</form>
)
当用户搜索时,我们使用他们的搜索 URL 查询发起对星球大战 API 的 API 调用:
const searchURL = 'https://swapi.dev/api/people/?search=';
const getInfo = () => {
console.log('Getting info from API...')
fetch(searchURL+query)
.then(res => res.json())
.then(data => setSearchResults(data.results))
.catch(e => {
console.log({error: e});
});
}
const handleInputChange = (e) => {
setQuery(e.target.value)
if (query && query.length > 0) {
getInfo();
}
}
如果 API 返回结果,我们会将ul
结果填充到搜索框下方的一个元素中。我通常使用标准的 map 方法,并key
为返回的 JSX 子元素创建一个 prop,但我想用一种新的方式实现它——使用React.Children.toArray()
.map 方法。这样,您就不必自己创建 key prop 了。
const results = React.Children.toArray(
searchResults.map((item,idx) => (
<li className='result-item' id={idx} onClick={handleQueryResultClick}>{item.name}</li>
))
)
看起来如下:
如果用户选择其中一个li
元素,则存储在原始结果数组中的该元素的索引searchResults
将与该元素的 id 匹配li
。
const handleQueryResultClick = (e) => {
const searchResultId = e.target.id;
setSelectedCharacter(searchResults[searchResultId]);
setQuery([]);
}
然后,我们将该角色搜索到的数据填充到搜索框下方的 div 中,并清除查询状态以移除ul
搜索结果元素。我使用了三元组来实现这一点。
<div>
{selectedCharacter ? (
<div className='character-display-container'>
<p><span className='character-info-title'>name:</span> {selectedCharacter.name}</p>
<p><span className='character-info-title'>height:</span> {selectedCharacter.height}</p>
<p><span className='character-info-title'>mass:</span> {selectedCharacter.mass}</p>
</div>
) : (
<p className='no-results-prompt'>There are no results. Try typing something into the search bar above.</p>
)}
</div>
就是这样!比我想象的要简单,主要是因为 API 非常容易使用。我强烈建议你尝试一下。
文章来源:https://dev.to/jameshubert_com/project-49-of-100-search-with-autocomplete-5g5f