config-router/README.md

300 lines
7.5 KiB
Markdown
Raw Normal View History

2021-10-23 15:40:28 +08:00
<center>
# 🎉 Config Router 🎉
[![中文文档](https://img.shields.io/static/v1?label=docs&message=简体中文&color=lightgrey&logo=markdown)](./README.CN.MD) ![English](https://img.shields.io/static/v1?label=current&message=English&color=brightgreen)
![Language](https://img.shields.io/github/languages/top/syy11cn/config-router?logo=typescript) ![License](https://img.shields.io/npm/l/@syy11cn/config-router) ![Version](https://img.shields.io/github/package-json/v/syy11cn/config-router?logo=npm) ![Contributors](https://img.shields.io/github/contributors/syy11cn/config-router?color=green) ![](https://img.shields.io/github/last-commit/syy11cn/config-router?color=blue&logo=github)
<p style="color: gray;">A route configuring, rendering and guarding lib based on React Router v5.x.</p>
</center>
<center>
## Why Config Router? :thinking:
</center>
**Config Router** :wave: is an attachment lib to _React Router v5.x_. It works well with React Router, helping with **route configuration, route rendering and route guarding**.
If you are a _Vue Router_ user before, it is quite easy for you to get started. Of course this project is not as mature as _Vue Router_. :joy:
<center>
## Features :tada:
</center>
- :heavy_check_mark: **Config route** by declaring the routes array like that in Vue Router.
- :heavy_check_mark: **Render routes** by importing and using a single component called **`RouterView`** :eyes:.
- :heavy_check_mark: **Guard routes** that should be accessed only by authorized users.
- :o: More is on the way...
<center>
## Usage :book:
</center>
You can use this package in either `react-jsx` projects or `react-tsx` projects. Take project with `vite`, `react` and `typescript` for example.
### Add `React Router` Dependencies
```bash
yarn add -s react-router-dom
yarn add -D @types/react-router-dom
```
> Or with `npm`.
>
> ```bash
> npm i -s react-router-dom
> npm i -D @types/react-router-dom
> ```
### Add `Config Router` Dependencies
After adding React Router dependencies, you can add `config-router` to your project.
```bash
yarn add -s @syy11cn/config-router
```
> Or with `npm`.
>
> ```bash
> npm i -s @syy11cn/config-router
> ```
### Create a Configuration File
Create a configuration file in `src/routes` (for example `config.ts`).
Here is a sample configuration.
```ts
// First you should import `routeType`.
import { routeType } from '@syy11cn/config-router';
// Import components to be used.
import Index from '../views/Index';
import Portal from '../views/Portal';
import Test from '../views/Test';
import Error from '../views/Error';
// Routes config.
const routes: Array<routeType> = [
{
path: '/home',
component: Index,
routes: [
{
path: '/home/test',
component: Portal,
},
{
path: '/home',
component: Test,
},
],
},
{
path: '/404',
component: Error,
},
{
path: '/',
component: Portal,
},
];
export default routes;
```
As shown above, routes config is an array consists of `routeType` items.
`routeType` is declared as follows,
```ts
import * as React from 'react';
interface routeType {
path: string;
component: React.ComponentType<any>;
exact?: boolean;
routes?: Array<routeType> | undefined;
}
export default routeType;
```
which means the `routes` field of an item is another `routeType` array.
**Prompt in Writing Configuration**
- The root route should always be the last item in a `routeType` array.
- Never set `exact: true` when there is a `routes` field in the `routeType` item.
- Fields `path` and `component` are required. Fields `exact` and `routes` are optional.
### Use `RouterView` Component
In `main.tsx`, add `<Router>` outside the `<App>` Component.
```tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter as Router } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<Router>
<App></App>
</Router>
</React.StrictMode>,
document.getElementById('root')
);
```
Then in `App.tsx`, use `RouterView` component.
```tsx
import { FunctionComponent } from 'react';
import { Layout } from 'antd';
import { RouterView } from '@syy11cn/config-router';
import routes from './routes/config';
import './App.css';
const { Header, Content, Footer } = Layout;
interface AppProps {}
const App: FunctionComponent<AppProps> = () => {
return (
<div className="App">
<Header></Header>
<Content>
<RouterView
routes={routes}
onEnter={function (to, next): void {
console.log('onEnter');
next();
}}
></RouterView>
</Content>
<Footer></Footer>
</div>
);
};
export default App;
```
The `RouterView` component here would render routes in the `<Content>` component. Rendered components would take the place of `RouterView`.
### Nested Routes
In the sample configuration, there is a nested route in component `Index`. **Notice that no matter where you use a `RouterView`, there should be a `routes` attribute added on it.**
Therefore, in `src/views/Index.tsx`, the component **should receive a `routes` property**, which includes nested routes under `Index` component.
```tsx
import { FunctionComponent } from 'react';
import { RouterView } from '../routes';
import { routeType } from '@syy11cn/config-router';
interface IndexProps {
routes: Array<routeType>;
props: any;
}
const Index: FunctionComponent<IndexProps> = ({ routes, props }) => {
console.log('Index View');
return (
<div>
<h1>This is Index</h1>
<RouterView
routes={routes}
onEnter={(to, next) => {
if (to === '/home/test') {
next();
} else {
next('/404');
}
}}
></RouterView>
</div>
);
};
export default Index;
```
### Route Guarding
Write a `Function` in `onEnter` hook, and the `Function` would be called before rendering the routes.
Your `Function` should receive two properties, which are named `to` and `next`.
- `to` is a `string` referring which route a user want to meet.
- `next` is a `Function`. If you pass a string to it, `next` would help you redirect to that path. While if you call `next` without passing a property, the component would just let user go where they want.
The same sample code as above.
```ts
import { FunctionComponent } from 'react';
import { RouterView } from '../routes';
import { routeType } from '@syy11cn/config-router';
interface IndexProps {
routes: Array<routeType>;
props: any;
}
const Index: FunctionComponent<IndexProps> = ({ routes, props }) => {
console.log('Index View');
return (
<div>
<h1>This is Index</h1>
<RouterView
routes={routes}
onEnter={(to, next) => {
if (to === '/home/test') {
next();
} else {
next('/404');
}
}}
></RouterView>
</div>
);
};
export default Index;
```
In this situation, when a user want to access `/home/test`, corresponding route and component would be rendered. When accessing `/home` or other routes begin with `/home`, the user would be redirect to a `404` page.
<center>
## Contribution :computer:
</center>
Contributions are welcome. Just fork this repo and send PRs.
Any questions while using this package, please open an [issue](https://github.com/syy11cn/config-router/issues) and I would manage to solve it as soon as I receive the message.
<center>
## About :raised_hands:
</center>
### License
[MIT](https://opensource.org/licenses/MIT)
Copyright (c) 2021, Yiyang Sun