ReactJS:如何在函数组件渲染前修改Redux状态以显示Loading?
React+Redux 全局Loading组件控制方案
问题场景
我有一个<Loading />组件,它包裹了应用中的所有路由。该组件通过isLoading属性接收Redux状态变量,以此控制自身的显示隐藏。当前代码如下:
function App() { const isLoading = useSelector((state) => state.loading.value) return ( <Loading isLoading={isLoading}> <BrowserRouter> <Routes> <Route path='/' element={<Hypertube />} /> <Route path='/login' element={<Login />} /> <Route path='/register' element={<Register />} /> </Routes> </BrowserRouter> </Loading> ); }
需求是:用户打开页面时,自动将Redux状态设为true显示Loading,页面渲染完成后再隐藏。原本想用已废弃的componentWillMount(),现在需要替代方案。我自己想到一个不太满意的方法:
- 将Redux状态默认值设为
true,实现首次加载显示 - 路由跳转时手动把状态改成
true
更优解决方案
1. 处理首次加载的显示与隐藏
使用useEffect钩子在组件挂载时初始化加载状态,然后监听页面加载完成事件(或组件渲染完成)来关闭Loading:
import { useDispatch, useSelector } from 'react-redux'; import { useEffect } from 'react'; function App() { const isLoading = useSelector((state) => state.loading.value); const dispatch = useDispatch(); useEffect(() => { // 组件挂载时立即开启加载状态 dispatch(setLoading(true)); // 监听页面所有资源(图片、脚本等)加载完成 const handlePageLoad = () => { dispatch(setLoading(false)); }; window.addEventListener('load', handlePageLoad); // 组件卸载时清理监听 return () => { window.removeEventListener('load', handlePageLoad); }; }, [dispatch]); return ( <Loading isLoading={isLoading}> <BrowserRouter> <Routes> <Route path='/' element={<Hypertube />} /> <Route path='/login' element={<Login />} /> <Route path='/register' element={<Register />} /> </Routes> </BrowserRouter> </Loading> ); }
如果不需要等待图片等资源,只需要组件渲染完成即可关闭Loading,改用setTimeout(利用宏任务特性,确保组件已渲染):
useEffect(() => { dispatch(setLoading(true)); // 等待组件渲染完成后关闭 const timer = setTimeout(() => { dispatch(setLoading(false)); }, 0); return () => clearTimeout(timer); }, [dispatch]);
2. 处理路由跳转时的加载状态
通过useLocation监听路由变化,触发加载状态:
import { useDispatch, useSelector } from 'react-redux'; import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; function App() { const isLoading = useSelector((state) => state.loading.value); const dispatch = useDispatch(); const location = useLocation(); // 路由变化时触发加载 useEffect(() => { dispatch(setLoading(true)); // 可根据实际页面加载时间调整延迟 const timer = setTimeout(() => { dispatch(setLoading(false)); }, 300); return () => clearTimeout(timer); }, [location.pathname, dispatch]); // 首次加载逻辑 useEffect(() => { dispatch(setLoading(true)); window.addEventListener('load', () => dispatch(setLoading(false))); return () => window.removeEventListener('load', () => dispatch(setLoading(false))); }, [dispatch]); return ( <Loading isLoading={isLoading}> <BrowserRouter> <Routes> <Route path='/' element={<Hypertube />} /> <Route path='/login' element={<Login />} /> <Route path='/register' element={<Register />} /> </Routes> </BrowserRouter> </Loading> ); }
懒加载组件的简化方案
如果你的路由组件是懒加载的,直接用React原生的Suspense组件,无需手动管理Redux状态:
import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { Suspense, lazy } from 'react'; // 懒加载路由组件 const Hypertube = lazy(() => import('./Hypertube')); const Login = lazy(() => import('./Login')); const Register = lazy(() => import('./Register')); function App() { return ( <BrowserRouter> {/* 组件加载完成前显示Loading */} <Suspense fallback={<Loading isLoading={true} />}> <Routes> <Route path='/' element={<Hypertube />} /> <Route path='/login' element={<Login />} /> <Route path='/register' element={<Register />} /> </Routes> </Suspense> </BrowserRouter> ); }
这种方式下,React会自动处理组件加载过程中的状态,代码更简洁。
内容的提问来源于stack exchange,提问作者arrmani88
相关产品推荐
相关产品推荐

