react如何控制全局loading
控制全局Loading的方法
在React中实现全局Loading控制,通常需要结合状态管理工具或上下文机制。以下是几种常见实现方式:
使用Context API
创建全局Loading状态上下文:
import React, { createContext, useContext, useState } from 'react';
const LoadingContext = createContext();
export const LoadingProvider = ({ children }) => {
const [isLoading, setIsLoading] = useState(false);
return (
<LoadingContext.Provider value={{ isLoading, setIsLoading }}>
{children}
</LoadingContext.Provider>
);
};
export const useLoading = () => useContext(LoadingContext);
在根组件中包裹Provider:
import { LoadingProvider } from './LoadingContext';
function App() {
return (
<LoadingProvider>
{/* 其他组件 */}
</LoadingProvider>
);
}
在需要的地方使用:
import { useLoading } from './LoadingContext';
function SomeComponent() {
const { isLoading, setIsLoading } = useLoading();
const fetchData = async () => {
setIsLoading(true);
await apiCall();
setIsLoading(false);
};
}
使用Redux管理状态
创建loading相关的action和reducer:
// actions.js
export const SET_LOADING = 'SET_LOADING';
export const setLoading = (isLoading) => ({
type: SET_LOADING,
payload: isLoading
});
// reducer.js
const initialState = { isLoading: false };
export const loadingReducer = (state = initialState, action) => {
switch(action.type) {
case SET_LOADING:
return { ...state, isLoading: action.payload };
default:
return state;
}
};
在组件中使用:
import { useDispatch, useSelector } from 'react-redux';
import { setLoading } from './actions';
function Component() {
const dispatch = useDispatch();
const isLoading = useSelector(state => state.loading.isLoading);
const handleClick = async () => {
dispatch(setLoading(true));
await fetchData();
dispatch(setLoading(false));
};
}
自定义Hook方案
创建可复用的loading hook:
import { useState } from 'react';
export const useGlobalLoading = () => {
const [loadingCount, setLoadingCount] = useState(0);
const isLoading = loadingCount > 0;
const showLoading = () => setLoadingCount(prev => prev + 1);
const hideLoading = () => setLoadingCount(prev => Math.max(0, prev - 1));
return { isLoading, showLoading, hideLoading };
};
拦截HTTP请求
通过axios拦截器实现自动loading控制:
import axios from 'axios';
import { useLoading } from './LoadingContext';
const api = axios.create();
export const setupInterceptors = (setLoading) => {
api.interceptors.request.use(config => {
setLoading(true);
return config;
});
api.interceptors.response.use(
response => {
setLoading(false);
return response;
},
error => {
setLoading(false);
return Promise.reject(error);
}
);
};
全局Loading组件实现
创建可复用的UI组件:
import React from 'react';
import { useLoading } from './LoadingContext';
export const GlobalLoading = () => {
const { isLoading } = useLoading();
if (!isLoading) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="text-white text-xl">Loading...</div>
</div>
);
};
在App组件中使用:
import { GlobalLoading } from './GlobalLoading';
function App() {
return (
<>
<GlobalLoading />
{/* 其他内容 */}
</>
);
}
注意事项
- 考虑使用防抖或延迟显示机制避免闪烁
- 对于并发请求场景,建议使用计数器而非布尔值
- 可以结合Promise或async/await简化代码
- 在SPA应用中注意路由切换时的loading状态清除
以上方案可根据项目规模和技术栈选择合适的方式组合使用。Context API适合中小型项目,Redux更适合复杂状态管理需求。







