You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+TS+Redux Toolkit页面重载时SearchFail组件闪现问题求助

问题描述

我有一个基于TS+React+Redux Toolkit的项目,会从接口获取数据存入items数组。在Main组件中,通过Redux Toolkit将filterMenu(字母/生日排序筛选)与filterSearch(搜索输入框)的数据传入filter状态,用于过滤数据。当过滤后的数组为空时,希望渲染SearchFail组件。

但页面重载时,SearchFail组件会短暂显示,之后才加载出数据。user切片状态包含isLoading、error和items,items初始状态为空数组,页面重载时数组长度为0,请问如何避免这种情况下SearchFail组件的加载?

解决方案

问题核心是初始加载阶段isLoading为false,同时items为空,导致逻辑误判为“过滤后无数据”。可以通过以下两种方式解决:

方式一:调整初始加载状态,优先显示骨架屏

修改user-slice.ts的初始状态,将isLoading设为true,同时从localStorage读取缓存数据(你已经在请求成功后把数据存在localStorage),让初始状态更合理:

// user-slice.ts
const initialState: IItmes = {
    // 优先从localStorage读取缓存,避免初始为空
    items: JSON.parse(localStorage.getItem('items') || '[]'),
    // 初始设为加载中,页面刚打开时直接显示骨架屏
    isLoading: true,
    error: ''
}

这样页面重载时,isLoading初始为true,会先渲染<SkeletonItem>,直到接口请求完成(或读取缓存后)才会切换到数据列表或SearchFail,避免了初始空数组触发SearchFail的问题。

方式二:在Main组件中增加“首次加载完成”的判断逻辑

如果不想修改初始isLoading,可以在Main组件中添加一个状态,标记是否已经完成第一次接口请求:

// Main.tsx
const Main: React.FC = () => {
    const { items, isLoading, error } = useAppSelector(state => state.user)
    const { filterSearch, filterMenu, filter } = useAppSelector(state => state.filter)
    const dispatch = useAppDispatch()
    // 新增状态:标记是否完成首次数据加载
    const [isFirstLoadComplete, setIsFirstLoadComplete] = useState(false)

    // 原filterItems逻辑不变
    const filterItems = filterMenu === 'alphabet' ? items.slice().sort((a,b) => a.firstName.localeCompare(b.firstName)).filter(item => {
        if (filterSearch === '') {
            return item
        } else {
            return item.firstName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                item.lastName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                item.userTag.toLowerCase().includes(filterSearch.toLowerCase())
        }
    }) : (
        items.slice().sort((a,b) => a.birthday.localeCompare(b.birthday)).filter(item => {
            if (filterSearch === '') {
                return item
            } else {
                return item.firstName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                    item.lastName.toLowerCase().includes(filterSearch.toLowerCase()) ||
                    item.userTag.toLowerCase().includes(filterSearch.toLowerCase())
            }
        })
    )

    useEffect(() => {
        const fetchData = async () => {
            await dispatch(getUsers(filter)).unwrap()
            setIsFirstLoadComplete(true)
        }
        fetchData()
        const timer = setInterval(() => {
            dispatch(getUsers(filter))
        }, 50000)
        return () => clearInterval(timer)
    }, [filter])

    return (
        <main className='main'>
            {error && <ErrorPage />}
            {isLoading ? <SkeletonItem count={6} /> :
                // 只有首次加载完成,且过滤后为空时,才显示SearchFail
                (isFirstLoadComplete && filterItems.length === 0) ? <SearchFail /> :
                    <div className="main__wrapper">
                        {filterItems.map(item => (
                            <MainItem data={item} key={item.id} />
                        ))}
                    </div>
            }
        </main>
    );
};

这种方式通过isFirstLoadComplete状态,确保只有在首次请求完成后,才会判断是否显示SearchFail,避免初始空数组的误判。

额外优化:提取重复过滤逻辑

你的filterItems中排序后的过滤逻辑完全重复,可以提取成单独函数,减少代码冗余:

// Main.tsx中新增过滤函数
const filterUserItems = (items: IUser[]) => {
    if (filterSearch === '') return items
    return items.filter(item => 
        item.firstName.toLowerCase().includes(filterSearch.toLowerCase()) ||
        item.lastName.toLowerCase().includes(filterSearch.toLowerCase()) ||
        item.userTag.toLowerCase().includes(filterSearch.toLowerCase())
    )
}

// 简化filterItems
const filterItems = filterMenu === 'alphabet' 
    ? filterUserItems([...items].sort((a,b) => a.firstName.localeCompare(b.firstName)))
    : filterUserItems([...items].sort((a,b) => a.birthday.localeCompare(b.birthday)))

(注:原代码中生日排序的逻辑有误,a.birthday.localeCompare(b.firstName)应改为a.birthday.localeCompare(b.birthday))

内容的提问来源于stack exchange,提问作者Anan Poinf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:44:59