1.7.0 • Published 3 years ago

@lxjx/react-router-manager v1.7.0

Weekly downloads
7
License
MIT
Repository
github
Last release
3 years ago

feature

  • support for routing level keepAlive, keep the route component states.
  • routing animation without performance loss
  • 404 custom、onRouteChange、route meta data、query parse、auth page、etc.
  • centrally manage route
  • conventional route

🎨example

loading...

📦install

npm install @lxjx/react-router-manager
# or
yarn add @lxjx/react-router-manager

🤔usage

basic

The most basic usage is almost the same as react router

import React from 'react';

import { HashRouter, Link } from "react-router-dom";

import {
  RouterManager, Route
} from '@lxjx/react-router-manager';

// pages
import Home from './home';
import About from './about';

function App() {
  return (
    <HashRouter>
      <RouterManager>
        <div>
          <Link to="/">home</Link>
          <Link to="/about">about</Link>
        </div>
        <Route 
            path="/" 
            component={Home} 
            exact // receive all Route props except for render、children
            />
        <Route
          path="/about"
          component={About}
        />
      </RouterManager>
    </HashRouter>
  );
}

export default App;

keepAlive

Pass in keepAlive so that a page will not be destroyed when it is unmounted

<XX>
    <Route path="/page1" keepAlive component={Page1} />
    <Route path="/page2" component={Page2} />
</XX>

use triggerPageUpdate to reload cached pages

triggerPageUpdate('/page1')

auth page

<RouterManager
   preInterceptor={({ location }) => {
   		if (!token && location.pathname !== '/login') return (
        	<div>Please log in first! <a href="/login">to login</a></div>
        )
   }}
</RouterManager>	

You can also use within prop

function withLogin(Component) {
    return function LoginHOC(props) {
        if (!token && props.location.pathname !== '/login') return (
        	<div>Please log in first! <a href="/login">to login</a></div>
        )
        
        return <Component {...props} />
    }
}

<Route component={Page2} path="/page2" within={[withLogin]} />

custom 404 page

function N404() {
  return <div>404</div>;
}

<RouterManager notFound={N404} >{...}</RouterManager>

page meta

<Route component={Page2} path="/page2" meta={{ title: 'page 2' }} />

// page component
function Page2({ meta }) {
    return (
    	<div>
        	<Helmet>
                <meta charSet="utf-8" />
                <title>{meta.title}</title>
                <link rel="canonical" href="http://mysite.com/example" />
            </Helmet>
        </div>
    )
}

events

<RouterManager
    onNotFound={({ location }) => {
        console.log('404', location.pathname);
    }}
    onRouteChange={({ location }) => {
        console.log('change', location.pathname);
    }}
    >
</RouterManager>

conventional route

Use convention routing, via webpack require.context API

  1. open config
<RouterManager conventionRouter></RouterManager>
  1. conventional dir
/proj
	/src
		/Index.jsx	// capitalize is require
		/News.jsx
		/About.jsx

// generated like =>
<Route path="/Index" exact component={/* Index.jsx module */}>
<Route path="/News" exact component={/* News.jsx module */}>
<Route path="/About" exact component={/* About.jsx module */}>
  1. complex construction
/proj
	/src
		/Index
			/Index.jsx		// => / 			exact
		/News				
			/News.jsx		// => /News			exact
			/Detail.jsx		// => /News/Detail
		/Center
			/Center.jsx		// => /Center		exact
			/Info.jsx		// => /Center/Info
  1. config by static prop
import React from 'react';

const Index = () => {
  return (
    <div>
      <div>Home Page</div>
    </div>
  );
};

Index.routerConfig = {
  keepAlive: true,
  meta: { title: 'home page' },
  // any Route Props
}

export default AddProduct;

typescript tips

Use RouteComponent to declare component

import React from 'react';
import { RouteComponent } from '@lxjx/react-router-manager';

type Props = {/* ... */};
type Query = {/* ... */};
type Param = {/* ... */};
type Meta = {/* ... */};
	
const Index: RouteComponent<Props, Query, Param, Meta> = ({
    match, // type ✅
}) => {
  return (
    <div>
      <div>Home Page</div>
    </div>
  );
};

// type ✅
Index.routerConfig = {
  keepAlive: true,
  meta: { title: 'home page' },
}

export default AddProduct;

static props

you can configure the route component with static properties

const Index: RouteComponent<Props, Query, Param, Meta> = () => {
  return (
    <div>
      <div>Home Page</div>
    </div>
  );
};

Index.routerConfig = {
  // pass any Route props
  keepAlive: true,
  meta: { title: 'home page' },
}

🎈API

RouterManager

manage Route components

export const RouterManager: React.FC<{
  /** custom 404 page components */
  notFound?: React.ComponentType<RouteComponentProps>;
  /** trigger on pathname not found */
  onNotFound?: ({ location: Location, history: History }) => void;
  /** trigger on pathname change */
  onRouteChange?: ({ location: Location, history: History }) => void;
  /** If reactElement or null is returned, prevent the routing node from rendering and render the returned node */
  preInterceptor?: (props: RMMatchProps) => React.ReactElement | null | void;
  /** Global Route props, covered by local props */
  routeBaseProps?: RMRouteProps;
  /** Use convention routing, via webpack require.context API */
  conventionRouter?: boolean;
  /** trigger on convention routing config created */
  onConventionRouterConfigCreated?: (conf: RMRouteProps[]) => void;
}>;

Route

Route components, used to configure a routing item, which is a superset of the Route component of react-router

export interface RMRouteProps extends RouteProps {
  /** animate transition type */
  transition?: 'bottom' | 'right' | 'fade';
  /** no destroy when page leave */
  keepAlive?: boolean;
  /** extra meta passed to the page component */
  meta?: { [key: string]: any };
  /** enhanced component, used for authentication, layout, etc. this hoc component should pass all received props like `<Component ...{props} />` */
  within?: RMWithinHOC[];
  /** page className */
  className?: string;
  /** page style, avoid using such as display、opacity、transform、z-index, etc. */
  style?: React.CSSProperties;
  /** route component */
  component?:
          | RouteComponent
          | React.ComponentType<RouteComponentProps>
          | React.ComponentType<any>;
}

RouteComponent

Used for routing component declaration

export interface RouteComponentProps<Query = any, Params = any, Meta = any> {
  match: match<Params> & { query: Partial<Query> };
  location: Location;
  history: History;
  meta: Meta;
  pageElRef: React.RefObject<HTMLDivElement>;
}

// with static config
export interface RouteComponent<
  Props = any,
  Query = any,
  Params = any,
  Meta = any
> extends React.FC<RouteComponentProps<Query, Params, Meta> & Props> {
  routerConfig: RMRouteProps;
}

triggerPageUpdate

invalid and overload the page cache of keepAlive

export const triggerPageUpdate: (path: string) => void;

🌹other

page base style

built-in basic styles for routing components that allow you to handle routing conveniently

.m78-router-wrap {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  overflow: hidden;
}

.m78-router-page {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  overflow: auto;
  background-color: #f6f6f6;
  -webkit-overflow-scrolling: touch;
}

it can:

  • prevent document flow confusion
  • no need to care about html, body, #root height, width...
  • scroll bars are maintained by the page itself, rather than using public document scroll bar, which can effectively prevent scrolling confusion
  • no need to lock the scroll bar of the document when modal/dialog is show
  • It is more convenient to manage pages

query

when the query is detected, the internal will be decoded by the query-string and mounted on the match object.

// http://xx.xx.cn/user?name=lxj&age=25

// component inside
props.match.query // => { name: 'lxj', age: 25 }