问题描述
一旦用户登录,他们就会被定向到门户 /portal
。我已将布局定义为:
export const UserLayout = ({ children }) => <div><Header /><div className="body">{children}</div></div>
这包括一个包含动态链接的标头,然后允许传递路由,因此不会在每次页面更改时加载标头。
export const UserRoutes = () => {
return (
<UserLayout>
<Switch>
<Route path="/portal" exact component={Portal}/>
<Route path="/settings" exact component={Settings}/>
</Switch>
</UserLayout>
);
}
头从 /login
重定向到 /portal
后首先加载。
我在 redux 中设置了一个全局加载器,它基本上在获取数据时显示全屏加载动画。
我遇到的主要问题是,如何在一个请求中加载应用程序的两个部分?
比如header加载ajax内容,显示redux加载动画,然后停止。然后路由加载,它也显示了一个 redux 加载动画,然后停止。这会产生闪烁效果。
解决方法
我不知道你的应用是如何构建的,但这会给你一个想法。您可以向 state
添加属性以控制待处理的请求。
const STATE = {
requests: []
...
}
定义基本的 actions
(您可以添加更多,例如请求取消等)。您需要知道请求何时开始以及何时结束:
const requestStartedAction = id => ({
type: REQUEST_STARTED,payload: { id } //--> something to identify the request
});
const requestEndedAction = id => ({
type: REQUEST_ENDED,payload: { id }
});
reducer
:
export default function(state = {},action) {
switch (action.type) {
case REQUEST_STARTED:
return {
...state,requests: [...state.requests,action.payload.id],//-> add a new request to the list
loading: true,};
case REQUEST_ENDED:
const pendingRequests = state.requests.filter(id => id!== action.payload.id); //--> remove request from the list
return {
...state,requests: pendingRequests,loading: !Boolean(pendingRequests.length),//--> don't hide the loading if there any request pending
};
...
}
}
然后,每次您发出请求时,您都会调用 requestStartedAction。当请求完成时,您可以调用 requestEndedAction。使用 fetch 的基本示例:
dispatch(requestStartedAction(ID));
fetch(URL).finally(() => dispatch(requestEndedAction(ID)));
如果请求列表为空,加载效果将停止。
,你不需要任何 redux...
import {lazy,Suspense} from 'react'
import {BrowserRouter,Switch,Route} from 'react-router-dom'
import Loader from './path/to/loader'
const Component1 = lazy(() => import('./path/to/component1')
const Component2 = lazy(() => import('./path/to/component2')
const Router = () => {
<Suspense fallback={<Loader/>}>
<BrowserRouter>
<Switch>
<Route path='/path1' component={Component1}/>
<Route path='/path2' component={Component2}/>
</Switch>
</BrowserRouter>
</Suspense>
}
如果这对您不起作用,那么您需要创建一个父级,该父级可以在呈现之前获取所需的所有数据并将其传递给子级,然后您可以在该父级中显示加载器。
如果您让全局组件在每次进行 fetch 调用时管理加载,您最终将始终处理闪烁或双重加载级联效应。
,here is the project with redux and a single loading
我做了一个加载减速器,在每个组件中如果需要获取数据,start-loading
被分派并将一个值推入加载数组,当数据被获取时,stop-loadig
被分派并赋值从数组中弹出。
const LoadingReducer = (state = initState,action) => {
const prevState = { ...state };
switch (action.type) {
case "START_LOADING":
prevState.loading.push(true);
return { ...state,prevState };
case "STOP_LOADING":
prevState.loading.pop(true);
return { ...state,prevState };
default:
return state;
}
};
在 App.js
中,我只是从商店获取加载并检查它是否有价值,然后决定是否显示 Loader
import { useEffect,useState } from "react";
import { connect } from "react-redux";
import UserRoutes from "./UserRoutes";
import Loader from "./Loader";
import "./styles.css";
const App = (props) => {
const [loading,setLoading] = useState(0);
useEffect(() => {
setLoading(props.loading);
},[props.loading]);
return (
<div className="App">
{loading && <Loader />}
<UserRoutes />
</div>
);
};
const mapStateToProps = (state) => {
return {
loading: state.LoadingReducer.loading.length > 0 ? true : false
};
};
export default connect(mapStateToProps,null)(App);