React路由的详解

Posted ZZZ --- jh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React路由的详解相关的知识,希望对你有一定的参考价值。

路由

当应用变得复杂时, 就需要分块进行处理和展示, 传统模式下, 我们是把整个应用分成了多个页面, 然后通过URL进行连接. 但是这种方式也有一些问题, 每次切换页面都需要重新发送所有请求和渲染整个页面, 不止性能上会有影响, 同时也会导致整个javascript重新执行,丢失状态.

SPA

概念

单页面应用, Single Page Application , 整个应用只加载一个页面(入口页面), 后续在与用户的交互过程中, 通过DOM操作在这个单页面上动态生成结构和内容.

优点

  • 有更好的用户体验(减少请求和渲染和页面跳转产生的等待与空白), 页面切换快
  • 重前端, 数据和页面内容由异步请求(ajax)+DOM操作来完成, 前端处理更多的业务逻辑

缺点

  • 首次进入处理慢
  • 不利于SEO(搜索引擎优化)

SPA的页面切换机制

虽然SPA的内容都是在一个页面通过JavaScript动态处理的, 但是还是需要根据需求在不同的情况下分内容展示, 如果仅仅只是依靠JavaScript内部机制去判断, 逻辑会变得过于复杂, 通过JavaScript与URL进行结合的方式: JavaScript根据URL的变化来处理不同的逻辑, 交互过程中只需要改变URL即可. 这样把不同URL与JavaScript对应的逻辑进行关联的方式就是路由, 其本质上与后端路由的思想是一致的.

前端路由

前端路由只是改变URL或URL中的某一部分, 但一定不会直接发送请求, 可以认为仅仅只是改变了浏览器地址栏上的URL而已, JavaScript通过各种手段处理这种URL的变化, 然后通过DOM操作动态的改变当前页面的结构

  • URL的变化不会直接发送HTTP请求
  • 业务逻辑由前端JavaScript来完成

目前前端路由的主要模式:

React Router

网址: https://reacttraining.com/react-router/

React Router 提供了多种不同环境下的路由库

  • web
  • native

基于Web的React Router

基于 web 的 React Router 为:react-router-dom

安装

npm i -S react-router-dom

组件

url的hash

  • URL的hash就是锚点,本质上是改变window.location的href属性;

  • 我们可以直接赋值location.hash来改变href,但是页面不发生刷新

  • <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <a href="#view1">视图1</a>
      <a href="#view2">视图2</a>
      <a href="#view3">视图3</a>
    
      <div id="view"></div>
    
      <script>
        function getHash()
          console.log(window.location.hash);
          view.innerHTML = window.location.hash;
        
        getHash();
        window.addEventListener('hashchange',getHash)
      </script>
    </body>
    </html>
    

以上这个案例点哪个按钮页面就会显示出来对应的锚点,控制台也会输出对应的

路由的类型: BrowserRouter 组件和HashRouter 组件,他俩得包裹着所有的内容

BrowserRouter 组件

基于 HTML5 History API 的路由组件

引入: import BrowserRouter from "react-router-dom";

HashRouter 组件

基于 URL Hash 的路由组件

引入: import HashRouter from "react-router-dom";

Route组件

通过该组件来设置应用单个路由信息, Route组件所在的区域就是当URL与当前Route设置的path属性匹配的时候, 后面component将要显示的区域.

path属性

匹配url;( 匹配url的方式不是相等, 而是以给定的url开头)

component属性

当url和前面的path匹配上的时候,compinent里面写显示的内容

exact属性

exact属性表示路由使用精确匹配模式, 非exact模式下’/’ 匹配所有以’/’ 开头的路由.

<!-- src/view/index.js -->
import React from "react";

export default function IndexPage()
  return <h1>首页</h1>


<!-- src/view/about.js -->
import React from "react";

export default function AboutPage()
  return <h1>关于我们</h1>
 

<!-- src/view/aboutMore.js -->
import React from "react";

export default function AboutMorePage()
  return <h1>详情</h1>

<!-- src/index.js -->
import React from 'react';
import ReactDOM from 'react-dom';
// import  HashRouter  from "react-router-dom";
import  BrowserRouter  from "react-router-dom";
import './index.css';
import App from './App';

ReactDOM.render(
  <BrowserRouter >
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);
<!-- src/app.js -->
import React from 'react';
import Route from "react-router-dom";
import IndexPage from "./view/index";
import AboutPage from "./view/about";
import AboutMorePage from "./view/aboutMore";

function App() 
  return (
    <div className="App">
      <Route path='/' exact component=IndexPage />
      <Route path='/about' exact component=AboutPage />
      <Route path='/about/more' exact component=AboutMorePage />
    </div>
  );


export default App;
Link组件

Link组件用来处理a链接类似的功能(它会在页面中生成一个a标签), 但设置这里需要注意的, react-router-dom拦截了实际a标签的默认动作, 然后根据所有使用的路由模式(Hash或者HTML5)来进行处理, 改变了URL, 但不会发生请求, 同时根据Route中的设置把对应的组件显示在指定的位置.

作用:

只改变url

to属性

to属性类似a标签中的href

<!-- src/component/nav.js -->
import React from 'react';
import  Link  from "react-router-dom";

export default function Nav()
  return(
    <nav>
      <Link to='/'>首页</Link>
      <span> |  </span>

      <Link to='/about'>关于我们</Link>
      <span> |  </span>

      <Link to='/about/more'>详情</Link>
      <span> |  </span>
    </nav>
  )

<!-- src/app.js -->
import React from 'react';
import Route from "react-router-dom";
import IndexPage from "./view/index";
import AboutPage from "./view/about";
import AboutMorePage from "./view/aboutMore";
import Nav from "./component/nav";

// path中: 匹配url的方式不是相等, 而是以给定的url开头


function App() 
  return (
    <div className="App">
      /* link组件 只改变url */
      <Nav />
      
      /* path属性: 匹配url */
      <Route path='/' exact component=IndexPage />
      <Route path='/about' exact component=AboutPage />
      <Route path='/about/more' exact component=AboutMorePage />
    </div>
  );


export default App;
传递props

如果 Route 使用的是 component 来指定组件,那么不能使用 props

render属性: 通过 render 属性来指定渲染函数,render 属性值是一个函数,当路由匹配的时候指定该函数进行渲染

import React, useState from 'react';

let [user,setUser] = useState('router');

<Route path='/' exact render=()=>
	return <IndexPage user=user setUser=setUser/>
 />

<!--src/view/index.js-->
import React from "react";

export default function IndexPage(props)
  console.log(props);
  let user,setUser = props;

  return <h1>
    <a onClick=()=>
      setUser('React可不')
    >啦啦</a>
    
    首页
  </h1>

动态路由

为了能给处理上面的动态路由地址的访问, 需要为Route组件配置特殊的path.

目的: 就是为了给不同的组件传递不同的参数

路由参数:

  • history: 历史记录以及路由给我们的一些操作

    goBack 返回上一步

    goForward 前进一步

    push: 修改当前的url

    replace: 修改当前的url

    // history.push(’/about’); //这个的回退功能是可以用的. 会增加历史记录

    // history.replace(’/about’); //这个没有回退一说. 不会增加历史记录

  • location: 获取当前url的一些信息

    • pathname – 当前的URL
    • search – 接口参数
    • state – 跳转路由时传递的参数
  • match: 当前路由匹配的相关规则

    • params – 动态路由传过来的参数
<!-- src/view/index.js -->
import React from "react";
import  NavLink, Link  from "react-router-dom";

export default function IndexPage()
  return (
    <div>
      <h1>留言列表</h1>

      <Link to='/list/1'>1</Link>
      <span> | </span>
      <Link to='/list/2'>2</Link>
      <span> | </span>
      <Link to='/list/3'>3</Link>
      <span> | </span>
      <Link to='/list/4'>4</Link>
      <span> | </span>
      <Link to='/list/5'>5</Link>
      <span> | </span>
      <Link to='/list/6'>6</Link>
    </div>
  )

<!-- app.js -->
import React from 'react';
import  Route,Switch  from "react-router-dom";
import IndexPage from "./view/index";
import Page404 from "./view/Page404";

function App() 
  return (
    <div className="App">
      <Switch>
        <Route path='/list/:page' exact render=(props)=>
          return <IndexPage ...props ></IndexPage>
        ></Route>

        <Page404 component=Page404></Page404>
      </Switch>
      
    </div>
  );

export default App;

以上的这个案例注意path路径写成动态的

NavLink组件

NavLink 与 Link类似, 但是它提供了两个特殊属性用来处理页面导航.

activeStyle

当当前URL 与 NavLink 中的to匹配时, 激活activeStyle中的样式

activeClassName

与 activeStyle 类似, 但是激活的是 className

<!-- src/component/nav.js -->
import React from 'react';
import  NavLink  from "react-router-dom";

export default function Nav()
  return(
    <nav>
      <NavLink 
        to='/'
        exact
        activeClassName='active'
        activeStyle=
          color:'red'
        
      >首页</NavLink>
      <span> |  </span>

      <NavLink 
        to='/about'
        exact
        activeClassName='active about'
        activeStyle=
          color:'red'
        
      >关于我们</NavLink>
      <span> |  </span>

      <NavLink 
        to='/about/more'
        exact
        activeClassName='active about more'
        activeStyle=
          color:'red'
        
      >详情</NavLink>
      <span> |  </span>
    </nav>
  )

isActive

默认情况下, 匹配的是URL 与 to的设置, 通过 isActive 可以自定义激活逻辑, isActive是一个函数, 返回布尔值

Switch组件

该组件只会渲染首个被匹配的组件

<!-- app.js -->
import React from 'react';
import  Route,Switch  from "react-router-dom";
import IndexPage from "./view/index";
import AboutPage from "./view/about";
import Page404 from "./view/Page404";

function App() 
  return (
    <div className="App">
      <Switch>
        <Route path='/' exact component=IndexPage></Route>
        <Route path='/about' exact component=AboutPage></Route>
        <Page404 component=Page404></Page404>
      </Switch>
    </div>
  );

export default App;

以上这个案例中要注意Page404写的顺序,如果写在Switch里面的最上面的话,不管加载哪个页面都只会出现页面飞走的内容,所以他要写在Switch里面的最下面.

Redirect组件

to属性: 设置跳转的URL

<!-- app.js -->
import React from 'react';
import  Route, Switch, Redirect  from "react-router-dom";
import IndexPage from "./view/index";
import Page404 from "./view/Page404";

function App() 
  return (
    <div className="App">
      <Switch>
        <Route path='/' exact render=()=>
          return <Redirect to='/list/1'></Redirect>
        ></Route>

        <Route path='/list/:page' exact render=(props)=>
          return <IndexPage ...props ></IndexPage>
        ></Route>

        <Page404 component=Page404></Page404>

      </Switch>
      
    </div>
  );

export default App;

以上这个案例目的就是让页面加载出来的时候就在page=1的页面中,并且让上面的地址栏里面显示的也是这个http://localhost:3000/list/1

withRouter组件(高阶组件, 高阶函数,高阶路由)

如果一个组件不是路由绑定组件,那么该组件的 props 中是没有路由相关对象的,虽然可以通过传参的方式传入,但是如果结构复杂,这样做会特别繁琐。所以就可以通过 withRouter 方法来注入路由对象

<!-- src/view/about.js -->
import React from "react";
import Inner from "./inner";

export default function AboutMorePage(props)
  let location,match = props;
  // console.log(match);

  return (
    <div>
      <h1>关于我们</h1>
      <Inner />
    </div>
  )

<!-- src/view/inner.js -->
import React from "react";
import  withRouter  from "react-router-dom";

function Inner(props)

  return (
    <div>
      <h1>Inner</h1>
      <button onClick=()=>
        console.log(props);
      >按钮</button>
    </div>
  )


export default withRouter(Inner);

hooks (Router5.0之后出现的)

  • 不在类组件内使用
  • useHistory : 获取History对象
  • useLocation : 获取Location对象
  • useParams : 获取Params
  • useRouteMatch : 获取Match

总结:

  • 路由有它的优点也有它的缺点
  • React Router 提供了web环境和native环境的路由库
  • 路由的类型: BrowserRouter 组件和HashRouter 组件

以上是关于React路由的详解的主要内容,如果未能解决你的问题,请参考以下文章

React路由的详解

React路由的详解

React路由的详解

React 路由概念详解

React路由超详解...

React 路由组件 详解