In addition to manually defined routing, Umi supports convention-based routing. This is also called file routing. It does not require manually configuring routes. Instead, the file system defines the routing. The routing configuration is derived from directories, files and their naming.
If there is no manual routing configuration file, Umi will fall back to the conventional routing mode, analyzing the src/pages directory to discover the routing configuration.
Consider the following file structure:
.└── pages├── index.tsx└── users.tsx
You will get the following routing configuration,
[{ exact: true, path: '/', component: '@/pages/index' },{ exact: true, path: '/users', component: '@/pages/users' },]
It should be noted that files that follow any of the following patterns will not be registered as routes:
. or _d.tstest.ts, spec.ts, e2e.ts (applicable to .js, .jsx and .tsx files)components and component directoriesutils and util directories.js, .jsx, .ts or .tsxPer convention, file path components enclosed in [] will be dynamically routed.
For example:
src/pages/users/[id].tsx becomes /users/:idsrc/pages/users/[id]/settings.tsx becomes /users/:id/settingsIn a more complete example, given the following file structure:
.└── pages└── [post]├── index.tsx└── comments.tsx└── users└── [id].tsx└── index.tsx
convention routing will produce the following routing configuration:
routes: [{ exact: true, path: '/', component: '@/pages/index' },{ exact: true, path: '/users/:id', component: '@/pages/users/[id]' },{ exact: true, path: '/:post/', component: '@/pages/[post]/index' },{exact: true,path: '/:post/comments',component: '@/pages/[post]/comments',},];
Per convention, file path components enclosed in [ $] will be dynamically optional routed.
For example:
src/pages/users/[id$].tsx becomes /users/:id?src/pages/users/[id$]/settings.tsx becomes /users/:id?/settingsIn a more complete example, given the following file structure:
.└── pages└── [post$]└── comments.tsx└── users└── [id$].tsx└── index.tsx
convention routing will produce the following routing configuration:
routes: [{ exact: true, path: '/', component: '@/pages/index' },{ exact: true, path: '/users/:id?', component: '@/pages/users/[id$]' },{exact: true,path: '/:post?/comments',component: '@/pages/[post$]/comments',},];
It is agreed in Umi that if there is _layout.tsx in the directory, a nested route will be generated, with _layout.tsx as the layout of the directory. The layout file needs to return a React component and render the child components through props.children.
For example, the following directory structure
.└── pages└── users├── _layout.tsx├── index.tsx└── list.tsx
will result in the following routing:
routes: [{ exact: false, path: '/users', component: '@/pages/users/_layout',routes: [{ exact: true, path: '/users', component: '@/pages/users/index' },{ exact: true, path: '/users/list', component: '@/pages/users/list' },]}]
The file src/layouts/index.tsx is used for the global route. It should return a React component that renders child components passed in props.children.
For example, the following directory structure,
.└── src├── layouts│ └── index.tsx└── pages├── index.tsx└── users.tsx
will result in the following routing:
routes: [{ exact: false, path: '/', component: '@/layouts/index',routes: [{ exact: true, path: '/', component: '@/pages/index' },{ exact: true, path: '/users', component: '@/pages/users' },],},]
A custom global layout could be defined as:
import { IRouteComponentProps } from 'umi'export default function Layout({ children, location, route, history, match }: IRouteComponentProps) {return children}
You may need to use different global layouts for different routes. Umi does not support different configuration files for that case, but you can still render different layouts based on the props.location.pathname attribute passed to the exported component in src/layouts/index.tsx.
For example, if you want to output a simple layout for /login,
export default function(props) {if (props.location.pathname === '/login') {return <SimpleLayout>{ props.children }</SimpleLayout>}return (<><Header />{ props.children }<Footer /></>);}
Umi will take the contents of src/pages/404.tsx for the 404 page. It is expected to return React components.
For example, the following directory structure,
.└── pages├── 404.tsx├── index.tsx└── users.tsx
corresponds to the routing
routes: [{ exact: true, path: '/', component: '@/pages/index' },{ exact: true, path: '/users', component: '@/pages/users' },{ component: '@/pages/404' },]
If a user visits /foo, neither / nor /users will match, which is why the router will fall back to the 404 route and render src/pages/404.tsx.
Routes can be protected by specifying high-level component wrappers.
For example, src/pages/user can define a wrappers property:
import React from 'react'function User() {return <>user profile</>}User.wrappers = ['@/wrappers/auth']export default User
See below example as content of src/wrappers/auth,
import { Redirect } from 'umi'export default (props) => {const { isLogin } = useAuth();if (isLogin) {return <div>{ props.children }</div>;} else {return <Redirect to="/login" />;}}
With the above configuration, user request to /user will be validated using the useAuth function. If successful, src/pages/user gets rendered, otherwise, the user will be redirected to /login.
Umi supports extending routing at the code level by exporting static attributes.
function HomePage() {return <h1>Home Page</h1>;}HomePage.title = 'Home Page';export default HomePage;
The title will be appended to the routing configuration.