我尝试在组件中使用useLocation
钩子:
import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { connect } from 'react-redux';
import { useNProgress } from '@tanem/react-nprogress';
import type { PayloadAction } from '@reduxjs/toolkit';
import type { AppState } from '@/store/app';
import { uiActions } from '@/store/reducers/ui';
import EDProgressBarView from './EDProgressBar.view';
interface IPropsFromState {
readonly isProgressBarVisible: boolean;
}
interface IPropsFromDispatch {
readonly closeProgressBar: () => PayloadAction;
}
interface IProps extends IPropsFromState, IPropsFromDispatch {}
const EDProgressBar: React.FC<IProps> = (props: React.PropsWithChildren<IProps>) => {
const { animationDuration, isFinished, progress } = useNProgress({
isAnimating: props.isProgressBarVisible,
incrementDuration: 200,
});
const location = useLocation();
useEffect(() => {
props.closeProgressBar();
}, [location]);
return (
<EDProgressBarView
animationDuration={animationDuration}
isFinished={isFinished}
progress={progress}
/>
);
};
EDProgressBar.displayName = 'EDProgressBar';
EDProgressBar.defaultProps = {};
const mapStateToProps = (state: AppState) => {
return {
isProgressBarVisible: state.ui.isProgressBarVisible,
};
};
export default connect(mapStateToProps, {
closeProgressBar: uiActions.closeProgressBar,
})(React.memo(EDProgressBar));
我把这个组件放在这里:
import React, { Suspense, useMemo } from 'react';
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import EDNotification from '@/ui/EDNotification';
import EDProgressBar from '@/ui/EDProgressBar';
import RouterBuilder from './App.router';
interface IProps {
readonly isAuthenticated: boolean | null;
}
const AppView: React.FC<IProps> = (props: React.PropsWithChildren<IProps>) => {
const routes = useMemo(() => {
return RouterBuilder(props.isAuthenticated);
}, [props.isAuthenticated]);
return (
<Suspense fallback={null}>
<RouterProvider router={createBrowserRouter(routes)} fallbackElement={null} />
<div id="backdrop-root" />
<div id="overlay-root" />
<EDNotification />
<EDProgressBar />
</Suspense>
);
};
AppView.displayName = 'AppView';
AppView.defaultProps = {};
export default React.memo(AppView);
然后我得到一个错误:
Uncaught Error: useLocation() may be used only in the context of a <Router> component.
但是我不明白如果RouterProvider
组件不接受类似组件的任何子组件来注入它,我怎么能做这样的事情。我需要这个EDProgressBar
组件存在于应用程序中,而不管活动路由是什么。我需要它存在于每个页面中。
我怎么能这样做呢?
这是我的RouterBuild:
import React from 'react';
import { type RouteObject } from 'react-router-dom';
const CliAuth = React.lazy(() => import('./pages/CliAuth'));
const CliAuthenticated = React.lazy(() => import('./pages/CliAuthenticated'));
const NotFound = React.lazy(() => import('./pages/NotFound'));
const RouterBuilder = (isAuthenticated: boolean | null) => {
const generalRoutes: RouteObject[] = [
{
path: 'cli-auth',
element: <CliAuth />,
},
{
path: 'cli-authenticated',
element: <CliAuthenticated />,
},
{
path: 'not-found',
element: <NotFound />,
},
{
path: '*',
element: isAuthenticated === null ? null : <NotFound />,
},
];
return [...(isAuthenticated ? authorizedRoutes : unAuthorizedRoutes), ...generalRoutes];
};
export default RouterBuilder;
注意,我删除了一些路由,因为它们在这里是无关紧要的,但重要的是,我在一些路由中使用了loader
键,所以我需要这个构建器。
1条答案
按热度按时间moiiocjp1#
useLocation
和其他RRD钩子不能在路由器提供的任何路由上下文之外使用。我建议创建一个布局路由来呈现EDNotification
和EDProgressBar
组件以及背景和覆盖div。这个布局路由将包含在RouterBuilder
返回的路由中。这允许访问路由上下文的组件在ReactTree中拥有比它们更高的路由器。示例: