Routing
FrontHub enables that you use routers inside your micro frontend environment. It is possible to use routers even though the application host has more than one micro frontend application running at the same time on the same page.
To do that FrontHub uses, configures react-router-dom
library and provides custom hooks in a way it can manage page transitions safely.
To start using a router in your micro frontend, just install react-router-dom
and use it.
yarn add react-router-dom
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Route } from 'react-router-dom'
import { useHistory } from '@resultadosdigitais/front-hub/react'
// All route props (match, location and history) are available to User
function User(props) {
return <h1>Hello {props.match.params.username}!</h1>
}
ReactDOM.render(
<Router history={history}>
<Route path="/user/:username" component={User} />
</Router>,
node,
)
History Hook
Beginning with version 9, Fronthub introduces a custom history hook designed to enhance, enable single-page application (SPA) navigation within shell applications, ensures smooth navigation transitions between micro frontends and eliminates issues that may arise when navigating between them. All micro frontends using Router functionality will need to utilize this hook. Fronthub will coordinate all micro frontends with a single Router, ensuring seamless navigation between micro frontends embedded within one another.
Using with Router
import { useHistory } from '@resultadosdigitais/front-hub/react'
import { Router, Route } from 'react-router-dom'
const Routes = () => {
const history = useHistory()
return (
<Router history={history}>
<Route path="/user/:username" component={User} />
<Route path="/dashboard" component={Dashboard} />
</Router>
)
}
Basename
Starting from version 9, Fronthub no longer supports the basename property from react-router-dom. Instead, it is necessary to manually add the route basename to each route.
Before:
return (
<Router basename="/app/settings/imports">
<Switch>
<Route path="/" exact>
<EmptyState />
</Route>
<Route path="/dados-gerais" exact>
<GeneralData />
</Route>
</Switch>
</Router>
)
Now:
const basename = '/app/settings/imports'
return (
<Router>
<Switch>
<Route path=`${basename/}` exact>
<EmptyState />
</Route>
<Route path=`${basename/dados-gerais}` exact>
<GeneralData />
</Route>
</Switch>
</Router>
)
SPA Routes and Application Host Configuration
For the microfrontend to be able to control the route, it must be passed on by the Application Host. This means that the route configuration on the backend will need to be done in a way that makes your SPA be rendered by the application host for all the routes that the microfrontend has. There are two ways to do this is by using a route with a wildcard
For example, consider an SPA with the following routes and components:
/users
- Component:UserListPage
/users/new
- Component:UserFormPage
/users/:userId
- Component:UserDetailPage
/users/:userId/groups
- Component:UserGroupPage
The SPA routing configuration code is as follows:
<Router history={history}>
<Switch>
<Route path={'/users/'} exact>
<UserListPage />
</Route>
<Route path={'/users/new'} exact>
<UserFormPage />
</Route>
<Route path={'/users/:userId'} exact>
<UserDetailPage />
</Route>
<Route path={'/users/:userId/groups'} exact>
<UserGroupPage />
</Route>
</Switch>
</Router>
Rendering with a Wildcard route - Ruby On Rails example
Using a wildcard can simplify the routing configuration. The routes.rb
would look something like the following:
get 'users/*', to: 'users#index'
By using a wildcard, you only need to add one method on the controller to respond to all routes:
class UsersController < SessionProtectedController
def index
render 'users/frontend/index'
end
end
How to navigate
Due to the implementation of the new shared history and the navigation between micro frontends using the new component, it will be necessary to adjust the navigation approach from what is commonly used in a few micro frontends.
With useHistory
hook (all history properties are available like in the react router documentation)
import { useHistory } from '@resultadosdigitais/front-hub/react'
import { Button } from '@resultadosdigitais/tangram-components'
///...other_imports
const YourComponent = () => {
const history = useHistory()
const handleRedirect = () => {
///...do_something
history.push('/the_route')
}
return (
<div>
<Button onClick={handleRedirect}>Redirect</Button>
</div>
)
}
With react-router-dom
Link
import { Link } from 'react-router-dom'
...other_imports
const YourComponent = () => {
return <Link to="/my-path">Hello</Link>
}
With Tangram and react-router-dom
Link
import { Link as LinkRouter } from 'react-router-dom'
import { Link } from '@resultadosdigitais/tangram-components'
export default function ExampleMyComponent() {
return (
<Link to="/my-path" as={LinkRouter}>
Hello
</Link>
)
}
You may consult the library documentation if you have any questions on how to use it.
As a side note, we do not support "state" property as it is a common source of bugs and as implemented today do not allow the end user to share urls.
You can read more information about it on the proposal Draft Frontend Architecture