基于React Hook 的 React Router4 路由统一配置管理(v4.0+ )

3,029 阅读4分钟

这篇博客是,基于react hook的脚手架,配合react-router-config react-router-dom来搭建的路由结构,简介,结构清晰,方便管理。。。

==demo已经发布到github上==

感觉可以的点一点star,谢谢咯!

写过vue的小伙伴都知道,vue的路由是在new Router 里统一配置的,写起来也特别爽,路由层次很清除,也很方便管理,然而react的路由相比较而言就有局限性,也不方便管理。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)
let roles = [
        {
            path: '/',
            component: home,
            redirect: '/home/first',
            children: allroutes()
        },
        {
            path: '/login',
            component: login
        },
        {
            path: '*',
            redirect: '/'
        }
    ]
const router = new Router({
    routes: roles
})
import React from 'react'
import { Router, Route, Link } from 'react-router'

const App = React.createClass({
  render() {
    return (
      <div>
        <h1>App</h1>
        <ul>
          <li><Link to="/about">About</Link></li>
          <li><Link to="/inbox">Inbox</Link></li>
        </ul>
        {this.props.children}
      </div>
    )
  }
})

const About = React.createClass({
  render() {
    return <h3>About</h3>
  }
})

const Inbox = React.createClass({
  render() {
    return (
      <div>
        <h2>Inbox</h2>
        {this.props.children || "Welcome to your Inbox"}
      </div>
    )
  }
})

const Message = React.createClass({
  render() {
    return <h3>Message {this.props.params.id}</h3>
  }
})

React.render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox}>
        <Route path="messages/:id" component={Message} />
      </Route>
    </Route>
  </Router>
), document.body)

而且4.0版本之前的react router中==Router==标签里不能嵌套其他标签,路由的灵活性就大打折扣,而且路由层次不清,尤其设计的路由嵌套的时候,看着也很乱。


下面我们借助 react-router-config 和 react-router-dom 就可以实现方便的统一管理的react路由配置。

1.搭个react基本项目

npm install -g create-react-app
create-react-app my-app
cd my-app/
npm start

2.安装我们需要的包 npm install react-router-config react-router-dom //看package.json是否成功

在这里插入图片描述
3.创建目录结构
在这里插入图片描述


一、router文件夹 - allrouters.js

路由可以跟写vue一样,层次分明,统一配置

import AllComponent from '../components'
import Home from '../components/Home'
import Child from '../components/Childs'
import First from '../components/Childs/First'
import Second from '../components/Childs/Second'
import Other from '../components/Other'
import Setting from '../components/Set'

const routes = [ {
        path: '/',
        component: AllComponent,//当组件下有子组件的时候要特别注意
        routes: [ {
                path: '/home',
                component: Home,
                routes: [],
            },
            {
                path: '/child',
                component: Child,
                routes: [ {
                        path: '/child/first',
                        component: First,
                        routes: []
                    },
                    {
                        path: '/child/second',
                        component: Second,
                        routes: []
                    }
                ],
            },
            {
                path: '/other',
                component: Other,
                routes: [],
            },
            {
                path: '/set',
                component: Setting,
                routes: [],
            },
        ],
    },
]
export default routes

一、router文件夹 - index.jsx

这里用的react-router-config,目的就是省去了我们遍历routes为==Route==标签的过程,

import React from 'react'
import { renderRoutes } from 'react-router-config'
import { BrowserRouter } from 'react-router-dom'
import routes  from './allroutes'

const Router = () => (
    <BrowserRouter>{renderRoutes(routes)}</BrowserRouter>
   //这个方法,每次有子路由时都需要使用,会传当前路由的子路由,可以说是按需加载,
       //实时编译的,而不是一次性吧所有路由都渲染出来
)
export default Router

上面的renderRoutes(routes),就是代替了下面的遍历过程。

 {routes.map((route, i) => (
      <Route
        key={route.key || i}
        path={route.path}
        exact={route.exact}
        strict={route.strict}
        render={(props) => {
          if (!route.requiresAuth || authed || route.path === authPath) {
            return <route.component {...props} {...extraProps} route={route} />
          }
          return <Redirect to={{ pathname: authPath, state: { from: props.location } }} />
        }}
      />
    ))}

二、components文件夹 - Sider文件夹 -index.jsx

这里就是正常的菜单,想在哪渲染就引入就好

import React, { memo } from 'react'
import { Link } from 'react-router-dom'

export default memo(function Sider() {
    return (
        <div className="route">
            <Link to="/home">首页</Link>
            <Link to="/child">孩子</Link>
            <Link to="/other">其他</Link>
            <Link to="/set">设置</Link>
        </div>
    )
})

二、components文件夹 - index.jsx


import React, { memo ,useEffect} from 'react'
import { renderRoutes } from 'react-router-config'
import { withRouter} from 'react-router-dom'
import Sider from './Sider'

export default memo(withRouter(function AllComponent(props) {
    console.log(props.route,'props.route',props.location)
    //这里可以使用react-router-dom里的,useLocation 和 useHistory 方法
    useEffect(() => {
        if(props.location.pathname === '/'){
            props.history.push('/home')
        }
    }, [props.location.pathname])
    return (
        <div>
            <Sider />
            <div className="content">
                {
                renderRoutes(props.route.routes) 
       //这个方法,每次有子路由时都需要使用,会传当前路由的子路由,可以说是按需加载,
       //实时编译的,而不是一次性吧所有路由都渲染出来
                }
            </div>
           
        </div>
    )
}))

二、components文件夹 -Childs文件夹- index.jsx

childs文件夹也是路由嵌套的,所以也用了renderRoutes(),就相当于,要渲染路由儿子,需要你指定儿子路由的位置。

import React, { memo ,useEffect } from 'react'
import { renderRoutes } from 'react-router-config'
import { Link } from 'react-router-dom'
import { withRouter} from 'react-router-dom'

export default memo(withRouter(function Index(props) {
    console.log(props.route.routes,'props.route.routes')
        useEffect(() => {
            if(props.location.pathname === '/child'){
                props.history.push('/child/first')
            }
            
        }, [props.location.pathname])
    return (
        <div>
            <div className="secondroute">
            <Link to="/child/first">第一个孩子</Link>
            <Link to="/child/second">第二个孩子</Link>
            </div>
            <div className="content">
                {renderRoutes(props.route.routes)}
        //这个方法,每次有子路由时都需要使用,会传当前路由的子路由,可以说是按需加载,
       //实时编译的,而不是一次性吧所有路由都渲染出来
            </div>
        </div>
    )
}))

二、components文件夹 -其他文件夹-index.jsx

类似于这样的一个简单的基础组件

import React, { memo } from 'react'

export default memo(function Other() {
    return (
        <div className="content">
            other
        </div>
    )
})

最终效果如下。

在这里插入图片描述

==demo已经发布到github上==

感觉可以的点一点star,谢谢咯!