React:react-router动态路由的使用及项目封装路由全过程

一、路由

1.安装

npm install --save react-router
npm install --save react-router-dom //5以上版本

2.作用

单页面刷新(SPA),切换显示视图

  • 初步使用方式:src/app.jsx页面
import React, {
      Component } from 'react'
import {
     
    BrowserRouter as Router,
    Route,
} from 'react-router-dom'

import Game from './components/game/paly'
import ComponentLife from './pages/ComponentLife'

export class App extends Component {
     
    render() {
     
        return (

            <div>
                <h3> 下面是使用路由来切换显示的方式 开始</h3>
                <Router>
                    <Route path='/Game' component={
     Game} />
                    <Route path='/ComponentLife' component={
     ComponentLife} />
                </Router>
                <h3> 这里是路由切换的结束 end</h3>
            </div>
        )
    }
}

export default App

3. 参考文档

react-router-github文档
router语法学习
官方学习文档

4. 注意点

  • 路由组件分为 BrowserRouter (history 模式) 和 HashRouter(哈希模式)
    • history 模式,路径没有#号,但是需要后台配置;
    • 哈希模式跳转有#号;
import {
      BrowserRouter as Router,Route,} from 'react-router-dom'
import {
      HashRouter as Router,Route,} from 'react-router-dom'
  • 路径从前往后如果有重复会显示所有匹配的,但是可以加:
    exact 精准匹配; strict 完全匹配
   <Route  exact  strict path='/game' component={
     ComponentLife} />
   <Route path='/game/routerDome' component={
     RouterDome} />
  • Switch只显示一个路由页面及不匹配显示404页面匹配规则
import React from 'react'
import {
     
    BrowserRouter as Router,
    Route,
    Switch,
    NavLink,
} from 'react-router-dom'

import Game from '../components/game/paly'
import NotFound from '../components/NotFound'
import ComponentLife from '../pages/ComponentLife'

const RouterIndex = () => {
     
    return (
        <div>
            <Router>
                <NavLink to='/game'>
                    <li>游戏, </li>
                </NavLink>
                <NavLink to='/componentLife'>
                    <li>生命周期,</li>
                </NavLink>
                </NavLink>
                <Switch>
                    <Route exact strict path='/game' component={
     Game} />
                    <Route exact path='/componentLife' component={
     ComponentLife} />
                    <Route exact component={
     NotFound}></Route>
                </Switch>
            </Router>
        </div>
    )
}
export default RouterIndex

  • 路由重定向 Redirect:当访问路由/laRedirect时,会直接重定向到/router/mine
import React from 'react'
import {
     
    BrowserRouter as Router,
    Route,
    Switch,
    NavLink,
    Redirect
} from 'react-router-dom'

import Game from '../components/game/paly'
import NotFound from '../components/NotFound'

const RouterIndex = () => {
     
    return (
        <div>
            <Router>
                <NavLink to='/game'>
                    <li>游戏, </li>
                </NavLink>
                <Switch>
                    <Route exact strict path='/game' component={
     Game} />
                    <Route exact component={
     NotFound}></Route>
                    <Redirect to="/router/mine" from="/laRedirect"></Redirect> 
                </Switch>
            </Router>
        </div>
    )
}
export default RouterIndex

5. 路由传参

  • 和vue类似,在路径上传递 :id,使用match接收
    <Router>
        <NavLink to='/router/mine'>
           <li> mine</li>
        </NavLink>
        <NavLink to='/router/UCenet/1000'>
           <li> ucenrt</li>
        </NavLink>
        <Switch>
            <Route exact={
     true} strict path='/router/mine' component={
     Mine} />
            <Route path='/router/UCenet/:id' component={
     UCenet} />
            {
     非必须写法}
            <Route path='/router/UCenet/?:id' component={
     UCenet} />
             {
     多参数写法}
            <Route path='/router/UCenet/?:id/:name' component={
     UCenet} />
            <Route component={
     NotFound}></Route>
        </Switch>
    </Router>
  • 编程式导航- 页面路由跳转同第8项,location.state接收
import React from 'react'
// 函数页面
const Mine = (props) => {
     
    const clickfunc = () => {
     
        props.history.push({
     
            pathname: '/router/UCenet/1050',
            search: '?some=search-string',
            state: {
     
                ['testState']: true
            }
        }
        )
    }
    return (
        <div>
            mine页面
            <button onClick={
     clickfunc}>去往另一个ucenet页面</button>
        </div>
    )
}
export default Mine

6. prompt

用于在用户离开页面之前及时提示用户。当你的应用程序进入应阻止用户离开的状态时(比如一个表格被填满了一半),渲染一个 。
formIsHalfFilledOut 布尔值

import {
      Prompt } from 'react-router'
<Prompt
  when={
     formIsHalfFilledOut}
  message="确认要离开吗?"
/>

7. 高阶组件 withRouter() 管理路由

作用:把不是通过路由切换过来的组件中,将react-router 的 history、location、match 三个对象传入props对象上;

默认情况下必须是经过路由匹配渲染的组件才存在this.props,才拥有路由参数,才能使用编程式导航的写法,执行this.props.history.push(’/detail’)跳转到对应路由的页面;

然而不是所有组件都直接与路由相连(通过路由跳转到此组件)的,当这些组件需要路由参数时,使用withRouter就可以给此组件传入路由参数,此时就可以使用this.props

设置withRouter很简单只需要两步:
-(1)引入
-(2)将App组件 withRouter() 一下即可

import React, {
      Component } from 'react'
import {
      withRouter } from 'react-router-dom'

class WithRouterDemo extends Component {
     
    render() {
     
        console.log(this.props);
        return (
            <div>
                <b> withRouterDemo页面</b>
            </div>
        )
    }
}
export default withRouter(WithRouterDemo)

8.编程式导航- 页面路由跳转

import React from 'react'
// 函数页面
const Mine = (props) => {
     
    const clickfunc = () => {
     
        // console.log(props);
        props.history.push(
            pathname:'/router/UCenet/1050',
            state: {
     
                identityId: 1
            })//push是下一个,回退还能找到,类似于vue中的路由push
        props.history.replace('/router/UCenet/50')//replace是替换,浏览器回退找不到
    }
    return (
        <div>
            mine页面
            <button onClick={
     clickfunc}>去往另一个ucenet页面</button>
        </div>
    )
}
export default Mine

history 对象通常会具有以下属性和方法:

length - (number 类型) history 堆栈的条目数
action - (string 类型) 当前的操作(PUSH, REPLACE, POP)
location - (object 类型) 当前的位置。location 会具有以下属性:
pathname - (string 类型) URL 路径
search - (string 类型) URL 中的查询字符串
hash - (string 类型) URL 的哈希片段
state - (object 类型) 提供给例如使用 push(path, state) 操作将 location 放入堆栈时的特定 location 状态。只在浏览器和内存历史中可用。
push(path, [state]) - (function 类型) 在 history 堆栈添加一个新条目
replace(path, [state]) - (function 类型) 替换在 history 堆栈中的当前条目
go(n) - (function 类型) 将 history 堆栈中的指针调整 n
goBack() - (function 类型) 等同于 go(-1)
goForward() - (function 类型) 等同于 go(1)
block(prompt) - (function 类型) 阻止跳转。 

注意,只有通过 Route 组件渲染的组件,才能在 this.props 上找到 history 对象

路由懒加载

React v16.6.0以上版本才支持React.lazy 和 Suspense。

// 页面导出的时候
import {
      BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, {
      Suspense, lazy } from 'react';const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));const App = () => (
  <Router>
    <Suspense fallback={
     <div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={
     Home}/>
        <Route path="/about" component={
     About}/>
      </Switch>
    </Suspense>
  </Router>
);

用插件-lazy中间层react路由懒加载(异步组件)------react-loadable

  • 安装包
cnpm install react-loadable
  • src/utils/Loadable.js,新建管理文件
import React from 'react';
import Loadable from 'react-loadable';

//通用的过场组件
const loadingComponent =()=>{
     
    return (
        <div>loading...</div>
    ) 
}

//过场组件默认采用通用的,若传入了loading,则采用传入的过场组件
export default (loader,loading = loadingComponent)=>{
     
    return Loadable({
     
        loader,
        loading
    });
}
  • sec/pages/home.jsx 页面调用
import React from 'react'
import {
      BrowserRouter, Route } from 'react-router-dom'
import loadable from '../util/loadable'

const Home = loadable(()=>import('@pages/home'))

const Routes = () => (
    <BrowserRouter>
        <Route path="/home" component={
     Home}/>
    </BrowserRouter>
);

export default Routes

二、路由的封装及懒加载

为什么要对路由进行封装呢?因为一个项目工程可能有上百个页面需要加载,每一次按照上述方式,在文件在使用route直接引用组件是很麻烦和不显示的,所以为了更好的维护,才需要进行封装路由及按需加载文件(懒加载)来更好的书写;
过程:

1.正常路由及懒加载路由单写法;
2.动态路由加载的路由总文件;
3.根路径index.js或APP.js的引入;

1.正常路由文件:src/router/firstRouter.js

import Game from '../components/game/paly'
import ComponentLife from '../pages/ComponentLife'
import AllTest from '../pages/AllTest'
import RouterDome from '../pages/RouterDome'
import Mine from '../pages/Mine'
import UCenet from '../pages/UCenet'

const firstRouter = [
    {
     
        path: "/",
        component: AllTest,
    },
    {
     
        path: "/alltest",
        redirect: '/',
    },
    {
     
        path: "/game",
        component: Game,
    },
    {
     
        path: "/componentLife",
        component: ComponentLife,
        meta: {
     
            id: 1
        }
    },
    {
     
        path: "/routerDome",
        component: RouterDome,
        routes: [
            {
     
                path: "/router/UCenet/1000",
                component: UCenet
            },
            {
     
                path: "/router/mine",
                component: Mine
            }
        ]
    }
]

export default firstRouter

2.懒加载路由文件:src/router/secondRouter.js

// 实现懒加载路由,而不是firstRouter中导入文件的方式
import React, {
      lazy } from 'react';
const secondRouter = [
    {
     
        path: "/redux",
        component: lazy(() => import("../components/redux/Parent")),
    },
    {
     
        path: "/reactRedux",
        component: lazy(() => import("../components/reactRedux/Parent")),
        // 可以传参,用于面包屑导航之类
        meta: {
     
            id: 1
        }
    },
    {
     
        path: "/hookDemo",
        component: lazy(() => import("../components/hookDemo/HookDemo")),
    }
]

export default secondRouter

3.动态路由加载的路由总文件:src/router/index.js

// 1.引入路由相关安装包
import React,{
     Suspense} from 'react'
import {
     
    BrowserRouter as Router,
    Route,
    NavLink,
    Redirect,
} from 'react-router-dom'

// 2.导入所有的路由文件
import NotFound from '../components/NotFound'
import firstRouter from './firstRouter'
import secondRouter from './secondRouter'
const routes = [
    ...firstRouter,
    ...secondRouter
]
//3.根据条件生成相应的组件
const RouteWithSubRoutes = route => {
     
    if (!route.path) return <Route component={
     NotFound} />
    return (<Route
        exact strict
        path={
     route.path}
        render={
     props => (
            route.redirect ?
                <Redirect push to={
     route.redirect} from={
     route.path}></Redirect> :
                <route.component {
     ...props} routes={
     route.routes} />
        )}
    />)
}
// 4.如果需要导航则使用link或navlink,一般情况可以不使用link/NavLink,在浏览器直接输入路由跳转同样生效 
// 5. Suspense这种方式只支持16.6以上的react,低版本react封装时候,可以参考上述的路由懒加载中的其他实现代码
const RouterIndex = () => {
     
    return (
        <div>
            <Router>
                   {
     /* 可选 开始 */}
                <NavLink to='/alltest'>
                    <li>所有的实例 </li>
                </NavLink>
                <NavLink to='/game'>
                    <li>游戏, </li>
                </NavLink>
                <NavLink to='/componentLife'>
                    <li>生命周期,</li>
                </NavLink>
                <NavLink to='/routerDome'>
                    <li>路由测试页面 </li>
                </NavLink>
                <NavLink to='/redux'>
                    <li>redux </li>
                </NavLink>
                <NavLink to='/reactRedux'>
                    <li>ReactRedux </li>
                </NavLink>
                <NavLink to='/hookDemo'>
                    <li>hookDemo </li>
                </NavLink>
                {
     /* 可选 结束 */}
                <Suspense fallback={
     <div>Loading...</div>}>
                    {
     routes.map((route, i) => <RouteWithSubRoutes key={
     i} {
     ...route} />)}
                </Suspense>
            </Router>
        </div>
    )
}
export default RouterIndex

4.根路径index.js或APP.js的引入:src/app.js

import React, {
      Component } from 'react'
import RouterIndex from './routers/index'
export default class App extends Component {
     
    render() {
     
        return (
            <div>
                <h3> 下面是使用路由来切换显示的方式 开始</h3>
                <RouterIndex />
                <h3> 这里是路由切换的结束 end</h3>
            </div>
        )
    }
}

其他问题

【已解决】ReactJS出错:Warning Failed prop type The prop history is marked as required in Router but its value is undefined

create-react-app 定义路径别名

结语

以上就是React:react-router路由的使用及封装过程~
其他博文请移步React专栏

如果本文对你有帮助的话,请不要忘记给我点赞评论打call哦~o( ̄▽ ̄)do
有问题留言 over~

你可能感兴趣的:(React,reactjs,javascript)