路由
路由信息,在/packages/app/client/.umirc.ts
中,只有一个路由地址。
routes: [{ path: '/', exact: false, component: '@/pages/index' }],
它的extac=false
表明nocobase
是所有的路由地址都经过@/pages/index
这个组件,便获取不到更多的信息了。
在/packages/core/client/src/application/Application.tsx
,通过Application
类下面的代码
this.use(RemoteRouteSwitchProvider, {
components: {
AuthLayout,
AdminLayout,
RouteSchemaComponent,
SigninPage,
SignupPage,
BlockTemplatePage,
BlockTemplateDetails,
},
});
找到RemoteRouteSwitchProvider
代码
export function RemoteRouteSwitchProvider(props: RouteSwitchProviderProps) {
const { data, loading } = useRequest({
url: 'uiRoutes:getAccessible',
});
if (loading) {
return <Spin />;
}
return <RouteSwitchProvider {...props} routes={data?.data || []} />;
}
上面获取到的data
数据
由此可以确定,这个函数就是获取路由的代码。
继续往下看,走到Application
的render
函数的return
return (
<ErrorBoundary FallbackComponent={ErrorFallback} onError={this.handleErrors}>
<App providers={this.providers} />
</ErrorBoundary>
);
再来看 App 函数的代码
const App = React.memo((props: any) => {
const C = compose(...props.providers)(() => {
const routes = useRoutes();
return (
<div>
<RouteSwitch routes={routes} />
</div>
);
});
return <C />;
});
在看RouteSwitch
可以看到它引用了react-router-dom
,版本使用是"react-router-dom": "^5.2.0"
function RouteSwitch() {
<Switch>
{routes.map((route, index) => {
if (route.type == 'redirect') {
return (
<Redirect
...
/>
);
}
if (!route.path && Array.isArray(route.routes)) {
route.path = route.routes.map((r) => r.path) as any;
}
return (
<Route
...
render={(props) => {
return (
<RouteContext.Provider value={route}>
<ComponentRenderer {...props} route={route} />
</RouteContext.Provider>
);
}}
/>
);
})}
</Switch>
}
从上面的代码可以看出,它的当route
的type=redirect
的时候使用Redirect
,其他使用Route
Redirect 组件介绍
类似于 HTTP 状态码 3xx,直接跳转。参数信息如下
to: string; // redirect到的地址
push: boolean; // true表示,redirect后会有历史记录
from: string; // 匹配需要redirect的地址
exact: boolean; // 是否精准匹配
strict: boolean; // 匹配路由后面的/,true表示/也必须匹配
在看回我们之前在控制台输出的 data,发现当路由是/
,跳转到/admin
上面代码在他的渲染Route
之前,有一个判断
if (!route.path && Array.isArray(route.routes)) {
route.path = route.routes.map((r) => r.path) as any;
}
通过 console 可以发现,他的singin
和signup
渲染的一个 ComponentRenderer
继续看下去会发现ComponentRenderer
实际上也是调用的RouteSwitch
<Component {...props}>
<RouteSwitch routes={props.route.routes} />
</Component>
所以他实际上就是一个递归,最后 path=array 还是在重复走一遍 routes.map,signin
和 signup
,最后还是单独渲染的自己组件
第一次routes.map
的return
的是一个['/signin', '/signup']
,通过递归第二次渲染routes.map
,signin
渲染的就是SinginPage
,signup
渲染的是SingnuPage