A Route manager for
react
can write routing configuration like vue-router in react. see: Nested Routes
Unlike 1.x,
[email protected]
does not depend on the react-router Library
npm install react-view-router --save
# or
yarn add react-view-router
/// router.js
import ReactViewRouter from 'react-view-router';
const router = new ReactViewRouter({
base: '', // the base URL of the app. For example, if the entire single page application is served under /app/, then base should use the value "/app/"
mode: 'hash', // or browser|memory|hash, default:hash
routes: [] // also can be passed by router.use method
});
export default router;
/// app.js
import React from 'react';
import { RouterView } from 'react-view-router';
import router from './router';
import routes from './routes';
router.use({ routes });
router.beforeEach((to, from, next) => {
if (to) {
console.log(
'%croute changed',
'background-color:#ccc;color:green;font-weight:bold;font-size:14px;',
to.url, to.query, to.meta, to.redirectedFrom
);
return next();
}
});
function App() {
const filter = routes => routes.filter(r => !r.meta.hide);
return (
<div>
<h1>App</h1>
<RouterView
router={router}
filter={filter}
fallback={<div>loading</div>}
/>
</div>
);
}
/// home/index.js
import React from 'react';
import { RouterView } from 'react-view-router';
export default function HomeIndex() {
return (
<div>
<h1>HomeIndex</h1>
<RouterView />
</div>
);
}
/// home/main/index.js
import React from 'react';
import { RouterView } from 'react-view-router';
export default function HomeMainIndex() {
return (
<div>
<h1>HomeMainIndex</h1>
<RouterView />
<RouterView name="footer" />
</div>
);
}
/// home/home/main/some/index.js
import React from 'react';
import { withRouteGuards } from 'react-view-router';
import store from 'store';
class HomeMainSomeIndex extends React.Component {
constructor(props) {
super(props);
this.state = { text: 'text1' };
}
refresh = () => {
this.setState({ text: 'text1 refreshed' })
}
render() {
let { text } = this.state;
return (
<div>
<h1>HomeMainSomeIndex</h1>
{ text }
</div>
);
}
}
export default withRouteGuards(HomeMainSomeIndex, {
beforeRouteEnter(to, from, next) {
if (!store.logined) next('/login');
else next(vm => vm.refresh());
},
beforeRouteLeave(to, from, next) {
// confirm leave prompt
next();
},
beforeRouteUpdate(to, from) {
},
afterRouteLeave(to, from) {
},
});
/// home/main/some/footer.js
import React from 'react';
export default function HomeMainSomeFooter() {
return (
<div>
<h1>HomeMainSomeFooter</h1>
</div>
)
}
/// login/index.js
import React from 'react';
import store from './store';
import router from './router';
export default function LoginIndex() {
const doLogin = () => {
store.logined = true;
router.push({
path: '/home',
query: { aa: 1 }
}, () => {
console.log('router.push is complete!');
}, () => {
console.log('router.push is abort!');
});
};
return (
<div>
<h1>LoginIndex</h1>
<button onClick={doLogin}>Login</button>
</div>
);
}
/// routes.js
import { normalizeRoutes, lazyImport } from 'react-view-router';
import Home from './home';
import Login from './login';
const routes = normalizeRoutes([
{
path: '/home',
component: Home
// children routes
children: [
// path redirect
{ path: '/', redirect: 'main' },
// or path index
// { path: '/', index: 'main' },
{
path: 'main',
// lazy load
component: lazyImport(() => import(/* webpackChunkName: "home" */ './home/main')),
// route meta infos
meta: { needLogin: true },
children: [
{ path: '/', redirect: to => ({ path: 'some', query: { aa: 1, bb: 2 } }) },
{
path: 'some',
components: {
default: lazyImport(() => import(/* webpackChunkName: "home" */ './home/main/some')),
footer: lazyImport(() => import(/* webpackChunkName: "home" */ './home/main/some/footer.js')),
}
// route guards:
beforeEnter(to, from, next) { next(); }
beforeLeave(to, from, next) { next(); }
beforeUpdate(to, from) {}
afterLeave(to, from) {}
}
]
}
]
},
{
path: '/login',
component: Login
}
])
path
URL string.component
React component.components
React components that be used forNamed RouterView
.exact
Whether only matches withlocation.pathname
exactly.strict
When true, a path that has a trailing slash will only match a location.pathname with a trailing slash. This has no effect when there are additional URL segments in the location.pathname.redirect
Navigates to new location, can be string, object or function.index
index route name, can be string or function.children
Nested child routes.meta
some custom route infos, see: Route Meta Fields.defaultProps
object{ aa: 1, bb: '2', cc: true }
, give some props into route component.props
boolean or object{ aa: Number, bb: String, cc: Boolean }
, Pass url params as a prop into route component.paramsProps
boolean or object{ aa: Number, bb: String, cc: Boolean }
, Pass url params as props into route component.queryProps
boolean or object{ aa: Number, bb: String, cc: Boolean }
, Pass url query as props into route component.guards
the route guards, see:Per-Route Guard
name
Use forNamed Views
, see vue-router instructionsfilter
is a function:function (routes: Array) { return [] }
that use for filter routesfallback
can be a functionfunction ({ parentRoute, currentRoute, inited, resolving, depth }) { return <div /> }
, orReact Component Element
like this:<Loading>loading</Loading>
RouterView.push(routes: Array): Array
add routes to RouterView instance, likeArray.push
;RouterView.splice(start[, deleteCount[, item1[, item2[, ...]]]]): Array
delete routes in RouterView instance, likeArray.splice
;RouterView.indexOf(route: String|Object): Number
checkroute
is in RouterView, likeArray.indexOf
RouterView.remove(route: String|Object): Object
removeroute
from RouterView, returnremoved route
orundefined
currentRoute
current matched route infos:
{
url: String,
// A string that equals the path of the current route, always resolved as an absolute path
path: String,
// The full resolved URL including query and hash.
fullPath: String,
// true if the path matches the location.pathname exactly.
isExart: Boolean,
// An Array containing route records for all nested path segments of the current route.
matched: [
route1,
// route2:
{
// the path from route config
path: String,
// the subpath from route config
subpath: String,
// the meta from route config
meta: Object,
// the redirect from route config
redirect: String|Object|Function,
// the original route config
config,
// the component instance that matched this route config if found.
componentInstances: {
default: React.Component,
/* others: React.Component */
}
// the RouterView instance that matched this route config if found.
viewInstances: {
default: RouterView
}
}
...,
routeN
],
// An object that contains key/value pairs of dynamic segments and star segments. If there are no params the value will be an empty object.
params: Object,
// An object that contains key/value pairs of the query string. For example, for a path /foo?user=1, we get currentRoute.query.user == 1. If there is no query the value will be an empty object.
query: Object,
// The name of the route being redirected from, if there were one
redirectedFrom: Object,
// The route abort function that passed by `router.push`, `router.replace`, `router.redirect`
onAbort: Function,
// The route complete function that passed by `router.push`, `router.replace`, `router.redirect`
onComplete: Function,
}
RouterLink
aNavLink
component likeroute-link
invue-router
.currentRoute
the current route that matched current url.initialRoute
the initial route when router be created.
beforeEach
global before guardsbeforeResolve
global brefore resolve guardsafterEach
global after guardspush
、replace
、go
、back
、forward
redirect
history navigation methodsparseQuery
、stringifyQuery
Provide custom query string parse / stringify functions, can be override bynew ReactViewRouter({ parseQuery: parseQueryMethod, stringifyQuery: stringifyQueryMethod });
install
ReactVueLike
plugin install methods. see: ReactVueLike
withRouteGuards
route component guards methods:
/**
* route component guards methods
* @param {Object} component - route component
* @param {Object} guards - guards methods
* @param {Class} [componentClass] - the route component class, it will be useful when component is High-order components
* @return {RouteComponentGuards} - the route componet that can be regarded as `React.forwardRef`
**/
function withRouteGuards(component, guards = {}, componentClass?) {}
lazyImport
route component lazy load method:
/**
* route component lazy load method
* @param {Function} importMethod - webpack lazy import method, For example: () => import('@/components/some-component')
* @return {RouteLazy} - the result only be used with component or components props in route config
**/
function lazyImport(importMethod) {}
normalizeRoutes
normalize route configs:
/**
* normalize route configs
* @param {Array} routes - unnormalized route configs
* @param {Object} [parent] - if provide, routes will be resolved regarded as parert`s children
* @return {Array} - normalized route configs
**/
function normalizeRoutes(routes, parent?) {}
normalizeLocation
normalize location string or object:
/**
* normalize location string or object
* @param {Object|string} to - location that need to normalize
* @param {Object} [route] - if provide, location will be resolved with route.parert
* @return {Object} - normalized location object: { path: string, pathname: string, search: string, query: Object, ...custom props }
**/
function normalizeLocation(to, route?) {}
isLocation
determine whetherv
is a location object
/**
* determine whether `v` is a location object
* @param {Object} v - the object to be determined
* @return {boolean}
**/
function isLocation(v) {}
matchPath
just re-export, see: matchPath
- if route component is
Class Component
(notFunction Component
), thenthis
variable inbeforeRouteUpdate
,beforeRouteLeave
,afterRouteLeave
Component Guards will be that component instance;