Router

TIP

The routing usage described below can be found in umi-examples/routes and find the sample code in umi-examples/routes-via-config.

Umi automatically generates routing configurations based on the pages directory.

Conventional Routing

Basic Routing

Assume that the pages directory structure is as follows:

+ pages/
  + users/
    - index.js
    - list.js
  - index.js

Then, umi will automatically generate the routing configuration as follows:

[
  { path: '/', component: './pages/index.js' },
  { path: '/users/', component: './pages/users/index.js' },
  { path: '/users/list', component: './pages/users/list.js' },
]

Dynamic Routing

As agreed in umi, directories or files with the $ prefix are dynamic routes.

For example, the following directory structure:

+ pages/
  + $post/
    - index.js
    - comments.js
  + users/
    $id.js
  - index.js

The routing configuration will be generated as follows:

[
  { path: '/', component: './pages/index.js' },
  { path: '/users/:id', component: './pages/users/$id.js' },
  { path: '/:post/', component: './pages/$post/index.js' },
  { path: '/:post/comments', component: './pages/$post/comments.js' },
]

Optional Dynamic Routing

In umi, dynamic routing is an optional dynamic route if it has a $ suffix.

For example, the following structure:

+ pages/
  + users/
    - $id$.js
  - index.js

The routing configuration will be generated as follows:

[
  { path: '/': component: './pages/index.js' },
  { path: '/users/:id?': component: './pages/users/$id$.js' },
]

Nested Routing

When there is _layout.js in the umi directory, a nested route will be generated, with _layout.js as the layout of the directory.

For example, the following directory structure:

+ pages/
  + users/
    - _layout.js
    - $id.js
    - index.js

The routing configuration will be generated as follows:

[
  { path: '/users', component: './pages/users/_layout.js',
    routes: [
     { path: '/users/', component: './pages/users/index.js' },
     { path: '/users/:id', component: './pages/users/$id.js' },
   ],
  },
]

Global Layout

The convention src/layouts/index.js is a global route, returning a React component, and rendering the child components via props.children.

Example:

export default function(props) {
  return (
    <>
      <Header />
      { props.children }
      <Footer />
    </>
  );
}

Different Global Layout

You may need to output a different global layout for different routes. umi does not support such a configuration, but you can still distinguish between location.path and render different layouts in layouts/index.js.

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 />
    </>
  );
}

404 Routing

The convention pages/404.js is a 404 page and needs to return a React component.

Example:

export default () => {
  return (
    <div>I am a customized 404 page</div>
  );
};

Note: In development mode, umi will add a default 404 page to aid development, but you can still verify the 404 page by precisely accessing /404.

Extending Routing by Annotation

The first comment of the contracted routing file is used to extend the route if it contains a configuration in the yaml format.

Example:

+ pages/
  - index.js

If pages/index.js contains:

/**
 * title: Index Page
 * Routes:
 *   - ./src/routes/a.js
 *   - ./src/routes/b.js
 */

A route configuration is generated:

[
  { path: '/', component: './index.js',
    title: 'Index Page',
    Routes: [ './src/routes/a.js', './src/routes/b.js' ],
  },
]

Configuration Routing

If you prefer to use a configured route, you can configure routes in the configuration file either .umirc.(ts|js) or config/config.(ts|js), this configuration item will not be parsed for the src/pages directory.

Example:

export default {
  routes: [
    { path: '/', component: './a' },
    { path: '/list', component: './b', Routes: ['./routes/PrivateRoute.js'] },
    { path: '/users', component: './users/_layout',
      routes: [
        { path: '/users/detail', component: './users/detail' },
        { path: '/users/:id', component: './users/id' }
      ]
    },
  ],
};

note:

  1. component is relative to the src/pages directory

Permission Routing

The permission routing of umi is implemented by configuring the Routes attribute of the route. The convention is added by the yaml annotation, and the configuration formula can be directly matched.

For example, the following configuration:

[
  { path: '/', component: './pages/index.js' },
  { path: '/list', component: './pages/list.js', Routes: ['./routes/PrivateRoute.js'] },
]

Then umi will render /list with ./routes/PrivateRoute.js.

Example of ./routes/PrivateRoute.js file:

export default (props) => {
  return (
    <div>
      <div>PrivateRoute (routes/PrivateRoute.js)</div>
      { props.children }
    </div>
  );
}

Route Transition Effects

There are several ways to implement route transition effects. Here is an example of react-transition-group.

Install dependencies first,

$ yarn add react-transition-group

In the layout component (layouts/index.js or _layout.js in the pages subdirectory), wrap a subassembly with TransitionGroup and CSSTransition and use location.pathname as the key.

import withRouter from 'umi/withRouter';
import { TransitionGroup, CSSTransition } from "react-transition-group";

export default withRouter(
  ({ location }) =>
    <TransitionGroup>
      <CSSTransition key={location.pathname} classNames="fade" timeout={300}>
        { children }
      </CSSTransition>
    </TransitionGroup>
)

The fade style used above can be defined in global.css under src:

.fade-enter {
  opacity: 0;
  z-index: 1;
}

.fade-enter.fade-enter-active {
  opacity: 1;
  transition: opacity 250ms ease-in;
}

There are many ways to implement breadcrumbs. Here is an example of react-router-breadcrumbs-hoc.

Install dependencies first,

$ yarn add react-router-breadcrumbs-hoc

Then implement a Breakcrumbs.js, such as:

import NavLink from 'umi/navlink';
import withBreadcrumbs from 'react-router-breadcrumbs-hoc';

// More configuration please go to https://github.com/icd2k3/react-router-breadcrumbs-hoc
const routes = [
  { path: '/', breadcrumb: 'home' },
  { path: '/list', breadcrumb: 'List Page' },
];

export default withBreadcrumbs(routes)(({ breadcrumbs }) => (
  <div>
    {breadcrumbs.map((breadcrumb, index) => (
      <span key={breadcrumb.key}>
        <NavLink to={breadcrumb.props.match.url}>
          {breadcrumb}
        </NavLink>
        {(index < breadcrumbs.length - 1) && <i> / </i>}
      </span>
    ))}
  </div>
));

Then introduce this React component where you need it.

Enable Hash Routing

Umi defaults to the Browser History. If you want to use Hash History, you need to configure:

export default {
  history: 'hash',
}

Scroll to Top

Decide whether to scroll to top in the componentDidUpdate of the layout component (layouts/index.js or the _layout.js in the pages subdirectory), for example:

import { Component } from 'react';
import withRouter from 'umi/withRouter';

class Layout extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0);
    }
  }
  render() {
    return this.props.children;
  }
}

export default withRouter(Layout);

Reference