Skip to main content

路由

路由信息,在/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数据

Untitled

由此可以确定,这个函数就是获取路由的代码。

继续往下看,走到Applicationrender函数的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>
}

从上面的代码可以看出,它的当routetype=redirect的时候使用Redirect,其他使用Route

Redirect 组件介绍

类似于 HTTP 状态码 3xx,直接跳转。参数信息如下

to: string; // redirect到的地址
push: boolean; // true表示,redirect后会有历史记录
from: string; // 匹配需要redirect的地址
exact: boolean; // 是否精准匹配
strict: boolean; // 匹配路由后面的/,true表示/也必须匹配

在看回我们之前在控制台输出的 data,发现当路由是/,跳转到/admin

Untitled

上面代码在他的渲染Route之前,有一个判断

if (!route.path && Array.isArray(route.routes)) {
route.path = route.routes.map((r) => r.path) as any;
}

通过 console 可以发现,他的singinsignup渲染的一个 ComponentRenderer

Untitled

继续看下去会发现ComponentRenderer实际上也是调用的RouteSwitch

<Component {...props}>
<RouteSwitch routes={props.route.routes} />
</Component>

所以他实际上就是一个递归,最后 path=array 还是在重复走一遍 routes.map,signinsignup,最后还是单独渲染的自己组件

Untitled

第一次routes.mapreturn的是一个['/signin', '/signup'],通过递归第二次渲染routes.mapsignin渲染的就是SinginPagesignup渲染的是SingnuPage

页面布局