React JS中如何在搜索进行时显示Spinner加载动画
问题分析
- 你的代码中连续同步调用
setIsSearching(true)和setIsSearching(false),React的状态更新是批量异步处理的,这两次更新会被合并,最终isSearching直接变为false,Spinner没有触发渲染的机会 - 缺少实际的搜索逻辑绑定,加载状态没有和搜索的执行周期挂钩,相当于开启加载后立刻关闭,自然看不到效果
正确实现方案
加载状态需要和搜索的完整执行周期绑定,在搜索开始前设为true,搜索结束(无论成功失败)后再设为false,以下是适配不同场景的实现方式:
1. 异步接口搜索(最常见场景)
适用于需要调用后端接口获取搜索结果的情况:
import { useState, useCallback } from 'react'; // 假设你已正确引入Input、Spinner组件 const [isSearching, setIsSearching] = useState(false); const [searchValue, setSearchValue] = useState(''); const [searchResult, setSearchResult] = useState([]); // 封装实际搜索请求逻辑 const fetchSearchResult = useCallback(async (keyword) => { // 替换为你的真实接口请求 const res = await fetch(`/api/search?q=${encodeURIComponent(keyword)}`); return await res.json(); }, []); const handleSearch = useCallback(async (e) => { const keyword = e.target.value; setSearchValue(keyword); // 空关键词直接重置 if (!keyword.trim()) { setSearchResult([]); return; } // 搜索开始前开启加载 setIsSearching(true); try { const result = await fetchSearchResult(keyword); setSearchResult(result); } catch (err) { console.error('搜索失败:', err); } finally { // 无论请求成功/失败,都关闭加载状态 setIsSearching(false); } }, [fetchSearchResult]); // 渲染逻辑 return ( <div> <Input onChange={handleSearch} value={searchValue} /> <Spinner style={{ display: isSearching ? 'block' : 'none' }} /> {/* 渲染搜索结果 */} {!isSearching && searchResult.map(item => ( <div key={item.id}>{item.content}</div> ))} </div> )
2. 实时输入搜索场景
如果是输入时实时触发搜索,建议添加防抖逻辑,避免频繁触发请求和加载闪烁:
import { debounce } from 'lodash'; // 也可以自行实现防抖函数 // 用防抖包装搜索逻辑,用户停止输入300ms后再发起请求 const debouncedFetch = useCallback( debounce(async (keyword) => { setIsSearching(true); try { const result = await fetchSearchResult(keyword); setSearchResult(result); } finally { setIsSearching(false); } }, 300), [fetchSearchResult] ); const handleInputChange = (e) => { const keyword = e.target.value; setSearchValue(keyword); if (!keyword.trim()) { setSearchResult([]); setIsSearching(false); return; } debouncedFetch(keyword); };
3. 本地同步搜索场景
如果是搜索前端已有的本地数据,本身耗时极短,通常不需要展示Spinner。如果一定要展示,可以加最小展示时长避免闪一下就消失:
const handleLocalSearch = async (keyword) => { setIsSearching(true); // 用Promise.all保证Spinner至少展示300ms const [result] = await Promise.all([ new Promise(resolve => { // 你的本地搜索逻辑 const res = localData.filter(item => item.title.includes(keyword)); resolve(res); }), new Promise(resolve => setTimeout(resolve, 300)) ]); setSearchResult(result); setIsSearching(false); };
内容的提问来源于stack exchange,提问作者Boidurja Talukdar
相关产品推荐
相关产品推荐

