react路由使用、相关概念

1. 对SPA的理解

  • 单页面web应用(single page web application,SPA)
  • 整个应用只有一个完整的页面
  • 点击页面中的链接不会刷新页面,只会做页面的局部更新

2.路由的理解

1.什么是路由
  • 一个路由就是一个映射关系(key:value)
  • key为路径,value可能是function或component
2.路由的分类
  1. 前端路由
    • 用来展示页面内容
    • 注册路由:<Route path="/login" component={Login}</Login>
    • 当浏览器的path变为/login时,当前路由组件就会变成 Login组件
  2. 后端路由
    • 用来处理客户端提交的请求
    • 注册路由:router.get(path,function(req,res))
    • 当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中函数来处理请求,返回相应数据
3.react-router-dom的理解
  • react的一个插件库
  • 专门用来实现一个SPA应用
  • react项目 基本都会用到的库
4.路由的基本使用
  1. 明确好页面中的导航区展示区

  2. 导航区:的a标签改为Link标签 <Link to="/xxx"></Link>

  3. 展示区:写Route标签进行路径匹配<Route path="/xxx" component={组件名}></Route>

  4. index.js文件中,<App/>标签的最外层包裹一个<BrowserRouter></BrowserRouter><HashRouter></HashRouter>,相当于整个应用的路由器

1、react-router-dom

  • react-router 核心库

  • react-router-dom DOM操作路由库

  • react-router-native ReactNative 的路由库

  • 文档地址:https://reactrouter.com/web/guides/quick-start

  • 如何使用

    npm i react-router-dom
    

2、基础语法

2.1、基础使用

  • 路由模式组件必须是顶层组件(所有的路由组件都必须在路由模式组件包裹范围之内!!!

  • 路由的配置

    <HashRouter>
      <Header/>
      <div className="container">
        <Switch>
            <Route path="/" exact component={Index} ></Route>
            <Route path="/about" component={About} ></Route>
            <Route path="/news" exact >
            		<News />
            </Route>
            <Route path="/news/:id" component={Info} ></Route>
            <Route path="/user"  component={User} ></Route>
            <Route path="/404">
            		<Notfound />
            </Route>
            {/* 404的配置,一定要放在最下方!!! */}
            <Route path="/*">
            		<Redirect to='/404' />
            </Route>
        </Switch>
    	</div>
    </HashRouter>
    
  • 常用组件

    • BrowserRouter history模式
    • HashRouter history模式
    • Route 路由映射组件
      • path
      • component
      • exact 严格模式
    • Switch 匹配到第一个匹配就跳出!
    • NavLink 导航链接,有激活class,默认为active!
      • exact
      • to
    • Link 普通链接
      • to
        • to='/地址'
        • to={pathname:'/地址',search:'?a=b&c=d',hash:'#e=f&g=h'}
    • Redirect
      • to 重定向

2.2、动态路由

  • 配置路由

    <Route path="/news/:id" component={Info} ></Route>
    
  • 设置链接

    <ul>
      <li><Link to='/news/111'>新闻111</Link></li>
      <li><Link to='/news/222'>新闻222</Link></li>
      <li><Link to='/news/333'>新闻333</Link></li>
      <li><Link to='/news/444'>新闻444</Link></li>
    </ul>
    
  • 获取参数(怎样获取动态路由的数据this.props.match.params)

    // 动态路由的数据!
    console.log(this.props.match.params)
    

    注意:

    使用Route组件建立映射关系,如果component属性指定了对应的组件!那么该组件的props里面将会包含路由相关信息!

    ​ 如果不是页面组件,或者页面组件不是通过component设立的,那么可以使用withRouter来进行数据的设置

    import React, { Component } from 'react';
    import { withRouter } from 'react-router-dom';
    
    class Notfound extends Component {
        render() {
            console.log(this)
            return (
                <div>
                    404页面
                </div>
            );
        }
    }
    
    export default withRouter(Notfound);
    
    

2.3、编程式导航

  • 编程式导航

    使用go的话必须要传参

     this.props.history.go()/goBack()/goForward()/replace()/push()
    
  • 如果在非组件里面的JS中使用编程式导航跳转

    • hash模式!推荐

      import { createHashHistory } from "history"
      const history = createHashHistory();
      history.go()/goBack()/goForward()/replace()/push()
      
    • history模式!

      // 顶级路由组件需要使用Router,且注入一个history实例,所有的跳转也是这个history实例
      
      // App.js
      import { Router,Redirect,Route,Switch } from "react-router-dom"
      import history "./history.js"
      
      <Router history={history}>
      		xxxxx
      </Router>
      
      // history.js文件
      import { createBrowserHistory } from "history"
      
      const history = createBrowserHistory();
      
      export default history;
      

      任意代码位置:

      import history "./history.js"
      history.go()/goBack()/goForward()/replace()/push()
      

2.4、嵌套路由

  • 嵌套路由的配置是写在对应的嵌套页面组件里面,而不是顶级
  • 嵌套路由的上级路由不能是严格模式!
  • 里面是path不是to!!!
import React, { Component } from 'react';
import { NavLink, Route, Switch } from 'react-router-dom';

import { createHashHistory } from "history"

import UserIndex from "./UserIndex"
import UserClass from "./UserClass"
import UserOrder from "./UserOrder"
import UserInfo from "./UserInfo"

let history = createHashHistory();

class User extends Component {
    quit=()=>{
        // this.props.history.push('/')
        history.push('/')
    }
    render() {
        return (
            <div className="main">
                <div className="nav">
                    <ul>
                        <li><NavLink activeClassName="on" to='/user/class'>我的课程</NavLink></li>
                        <li><NavLink activeClassName="on" to='/user/order'>我的订单</NavLink></li>
                        <li><NavLink activeClassName="on" to='/user/info'>我的资料</NavLink></li>
                    </ul>
                </div>
                <div className="box">
                    <div>
                        <div>欢迎您:<button onClick={this.quit}>退出</button></div>
                        <hr/>
                        {/* 主体内容 */}
                        <Switch>
                            <Route path="/user/" exact component={UserIndex}></Route>
                            <Route path="/user/order" component={UserOrder}></Route>
                            <Route path="/user/class" component={UserClass}></Route>
                            <Route path="/user/info" component={UserInfo}></Route>
                        </Switch>
                    </div>
                </div>
            </div>
        );
    }
}

// 嵌套路由:
    // 嵌套路由的配置是写在对应的嵌套页面组件里面,而不是顶级!
    // 嵌套路由的上级路由不能是严格模式!

export default User;

2.5、导航守卫

  • 思路: 让所有Route组件渲染的时候都走同一个函数,在这个函数里面去做拦截!

  • 实现:

    • 思路引导1

      class MyRouter extends Component {
          render() {
              return (
                  <Switch>
                      <Route path="/" exact render={() => <Index/> } ></Route>
                  </Switch>
              );
          }
      }
      
    • 思路引导2

      class MyRouter extends Component {
          renderCom=(val)=>{
              return val
          }
          render() {
              return (
                  <Switch>
                      <Route path="/" exact render={() =>this.renderCom(<Index/>)} ></Route>
                      <Route path="/about"  render={() =>this.renderCom(<About/>)} ></Route>
                      <Route path="/news"   render={() =>this.renderCom(<News/>)} ></Route>     
                  </Switch>
              );
          }
      }
      

      使用render去渲染组件,组件当然也没有了props!可以使用withRouter来进行处理!

    • 思路引导3

      // 路由的配置信息!
      const routeConfig = [
          { path: "/", exact: true, component: <Index />, title: "首页" },
          {path:"/about",exact:false, component:<About/>,title:"关于我们"},
          { path: "/news", exact: true, component:<News/>,title:"新闻列表"},
          { path: "/news/:id", exact: false, component: <Info />, title: "新闻详情" },
          { path: "/user", exact: false, component: <User />, title: "用户中心",needLogin:true },
          { path: "/login", exact: false, component: <Login />, title: "登录" },
          { path: "/404", exact: false, component: <Notfound />, title: "404页面" },
          { path: "/*", exact: false,redirect:"/404"}
      ]
      
      class MyRouter extends Component {
          renderCom=(val)=>{
              document.title = val.title
              if(val.redirect){
                  return <Redirect to={val.redirect} />
              }else{
                  // 这里!!! 要做判断!登录判断,权限判断!!!
                  if (val.needLogin){
                      if (localStorage.getItem('userinfo')) {
                          return val.component;
                      } else {
                          return <Redirect to="/login" />
                      }
                  }else{
                      return val.component;
                  }
              }
          }
          render() {
              return (
                  <Switch>
                      {/* <Route path="/" exact render={() =>this.renderCom(<Index/>)} ></Route>
                      <Route path="/about"  render={() =>this.renderCom(<About/>)} ></Route>
                      <Route path="/news"   render={() =>this.renderCom(<News/>)} ></Route> */}
                      {routeConfig.map((val,idx)=>{
                          return <Route key={idx} path={val.path} exact={val.exact} render={() => this.renderCom(val)} ></Route>
                      })}
                  </Switch>
              );
          }
      }
      
      export default MyRouter;
      // 让所有的组件都走renderCom函数,在这个函数里面去做标题设置、权限判断、等等,符合条件就返回对应的组件内容。
      

2.6、路由懒加载

  • 核心插件:react-loadable

  • 文档地址:https://www.npmjs.com/package/react-loadable

  • 使用

    yarn add react-loadable
    // 或者
    npm i react-loadable
    
    import Loadable from 'react-loadable';
    import Loading from './my-loading-component';   // 自定义等待组件
     
    const LoadableComponent = Loadable({
      loader: () => import('./my-component'),
      loading: Loading,
    });
    
    /*
    const  异步组件 = Loadable({
    	loader:()=>import('组件')
    	loading:等待组件
    })
    */
    

    示例

    import Loadable from 'react-loadable';
    import Loading from '../components/Loading'; 
    
    // import Index from "../pages/Index"
    // import About from "../pages/About"
    // import News from "../pages/News"
    // import Info from "../pages/Info"
    // import User from "../pages/User"
    // import Notfound from "../pages/Notfound"
    // import Login from "../pages/Login"    
    
    const Index = Loadable({ loader: () => import("../pages/Index"), loading: Loading })
    const About = Loadable({ loader: () => import("../pages/About"), loading: Loading })
    const News = Loadable({ loader: () => import("../pages/News"), loading: Loading })
    const User = Loadable({ loader: () => import("../pages/User"), loading: Loading })
    const Notfound = Loadable({ loader: () => import("../pages/Notfound"), loading: Loading })
    const Login = Loadable({ loader: () => import("../pages/Login"), loading: Loading })
    const Info = Loadable({ loader: () => import("../pages/Info"), loading: Loading})
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值