Redux+Hook实现React的全局Loader
使用Redux + 自定义Hook
准备 Loader
Loader.tsx 文件
import React from 'react';
import styled from 'styled-components';
const Loader = () => {
return (
<StyledWrapper>
<span className="loader" />
</StyledWrapper>
);
}
import React from 'react';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import Loader from './loader';
import { selectLoading } from '@/store/features/loader/loaderSlice';
const GlobalLoader = () => {
// 从Redux状态中获取loading状态
const isLoading = useSelector(selectLoading);
// 如果不在加载状态,则不渲染任何内容
if (!isLoading) return null;
return (
<LoaderOverlay>
<Loader />
</LoaderOverlay>
);
};
const LoaderOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.1);
z-index: 9999; // 确保Loader显示在所有内容之上
`;
export default GlobalLoader;
use——loader.tsx
import { useDispatch } from 'react-redux';
import { showLoader, hideLoader } from '@/store/features/loader/loaderSlice';
/**
* 自定义Hook,用于控制全局加载状态
* @returns 包含显示和隐藏加载器的方法的对象
*/
export const useLoader = () => {
const dispatch = useDispatch();
// 显示全局加载器
const showGlobalLoader = () => {
dispatch(showLoader());
};
// 隐藏全局加载器
const hideGlobalLoader = () => {
dispatch(hideLoader());
};
return {
showGlobalLoader,
hideGlobalLoader,
};
};
全局Loader
global-loader.tsx
import React from 'react';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import Loader from './loader';
import { selectLoading } from '@/store/features/loader/loaderSlice';
const GlobalLoader = () => {
// 从Redux状态中获取loading状态
const isLoading = useSelector(selectLoading);
// 如果不在加载状态,则不渲染任何内容
if (!isLoading) return null;
return (
<LoaderOverlay>
<Loader />
</LoaderOverlay>
);
};
const LoaderOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.1);
z-index: 9999; // 确保Loader显示在所有内容之上
`;
export default GlobalLoader;
提供全局加载状态的UI展示
这个组件应该被放置在应用的根组件中,以确保加载状态可以在整个应用中显示
loader-provider.tsx
import React from 'react';
import GlobalLoader from './global-loader';
/**
* LoaderProvider组件
* 提供全局加载状态的UI展示
* 这个组件应该被放置在应用的根组件中,以确保加载状态可以在整个应用中显示
*/
export const LoaderProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
return (
<>
<GlobalLoader />
{children}
</>
);
};
根组件加载
export default function Providers({children}: { children: React.ReactNode }) {
return (
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<Provider store={store}>
<LoaderProvider>
<App/>
{children}
<RouterProvider router={router}/>
<Toaster/>
</LoaderProvider>
</Provider>
</ThemeProvider>
);
}
实例
import React from 'react';
import { Button } from '@/components/ui/button';
import { useLoader } from '@/hooks/use-loader';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import Loader from "@/components/loader/loader.tsx";
/**
* Loader示例组件
* 展示如何使用useLoader hook控制全局加载状态
*/
const LoaderExample = () => {
// 使用自定义Hook获取加载器控制方法
const { showGlobalLoader, hideGlobalLoader } = useLoader();
// 模拟异步操作
const simulateAsyncOperation = () => {
showGlobalLoader(); // 显示加载器
// 3秒后自动隐藏加载器
setTimeout(() => {
hideGlobalLoader();
}, 3000);
};
return (
<div className="container py-10">
<h1 className="text-2xl font-bold mb-6">全局加载器示例</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle>基本用法</CardTitle>
<CardDescription>
点击按钮显示全局加载器,3秒后自动隐藏
</CardDescription>
</CardHeader>
<CardContent>
<Button onClick={simulateAsyncOperation}>
显示加载器 (3秒)
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>手动控制</CardTitle>
<CardDescription>
分别使用按钮手动控制加载器的显示和隐藏
</CardDescription>
</CardHeader>
<CardContent className="flex gap-4">
<Loader/>
<Button onClick={showGlobalLoader} variant="default">
显示加载器
</Button>
<Button onClick={hideGlobalLoader} variant="outline">
隐藏加载器
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>实际应用场景</CardTitle>
<CardDescription>
在数据加载过程中显示加载状态
</CardDescription>
</CardHeader>
<CardContent>
<Button
onClick={() => {
showGlobalLoader();
// 模拟API请求
setTimeout(() => {
hideGlobalLoader();
// 显示成功消息
alert('数据加载成功!');
}, 2000);
}}
>
加载数据
</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>表单提交示例</CardTitle>
<CardDescription>
在表单提交过程中显示加载状态
</CardDescription>
</CardHeader>
<CardContent>
<Button
onClick={() => {
showGlobalLoader();
// 模拟表单提交
setTimeout(() => {
hideGlobalLoader();
// 显示成功消息
alert('表单提交成功!');
}, 1500);
}}
>
提交表单
</Button>
</CardContent>
</Card>
</div>
<div className="mt-8 p-4 bg-gray-100 rounded-md">
<h2 className="text-lg font-semibold mb-2">使用说明</h2>
<p className="mb-2">1. 导入useLoader hook:<code>import {'{ useLoader }'} from '@/hooks/use-loader';</code></p>
<p className="mb-2">2. 在组件中使用hook:<code>const {'{ showGlobalLoader, hideGlobalLoader }'} = useLoader();</code></p>
<p className="mb-2">3. 调用方法显示/隐藏加载器:<code>showGlobalLoader()</code> 和 <code>hideGlobalLoader()</code></p>
<p>4. 确保在应用根组件中已引入GlobalLoader组件</p>
</div>
</div>
);
};
export default LoaderExample;
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 byxl8112!
评论




