React路由-react-router-dom安装与使用(一)

1、路由
当应用变得复杂的时候,就需要分块的进行处理和展示。
传统方式的处理: 把整个应用分成了多个页面,然后通过 URL 进行连接。

传统方式的弊端:

  • 每次切换页面都需要重新发送所有请求和渲染整个页面,性能上会有影响;
  • 会导致整个 JavaScript 重新执行,丢失状态。

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

**单页面应用优缺点**如下:

优点 缺点
有更好的用户体验(减少请求、渲染以及页面跳转等待),页面切换快 首次进入页面处理比较慢(请求减少,在同一页面内容就增多了,加载时间随之增加)
数据和页面内容由异步请求(AJAX)+ DOM 操作来完成,前端处理更多的业务逻辑 不利于搜索引擎优化(SEO)

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

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

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

目前前端路由主要的模式

  • 基于 URL Hash 的路由
  • 基于 HTML5 History API 的路由
    开发环境下(上线前),在地址栏url中后者比前者多了一个#,其他没有什么差别;
    参考https://www.cnblogs.com/GGbondLearn/p/12239651.html

React Router
基于 web 的 React Router 为:react-router-dom
安装
npm i -S react-router-dom

BrowserRouter 组件
基于 HTML5 History API 的路由组件

HashRouter 组件
基于 URL Hash 的路由组件
示例:简单的tab选项卡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>hash值的使用-简单tab选项卡</title>
</head>
<body>
    <a href="#first">one</a>
    <a href="#second">two</a>
    <a href="#third">three</a>
    <div id="box"></div>
    <script>
        function getHash(params) {
            console.log(window.location.hash);
            box.innerHTML = window.location.hash;
        } 
        // 监听hashchange事件,当hash值发生改变时,调用getHash方法
        window.addEventListener("hashchange",getHash);
    </script>
</body>
</html>

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

import React from 'react';
//index.js
export default function Index(){ 
    return (<h1>首页</h1>);
}
import React from 'react';
//about.js
export default function About(){ 
    return (<h1>关于我们</h1>);
}
import React from 'react';
import {Route} from 'react-router-dom';
import Index from './view/index';
import About from './view/about';
//App.js
export default function App(){ 
    return (
       <div>
          <Route path="/" component={Index} />
          <Route path="/about" component={About} />
          <Route path="/about/more" component={More}/>
       </div>
    );
}

运行后,浏览器控制台报错如下:
路由最外层需要被包裹着
翻译一下:未捕获错误:不变式失败:你不应该在一个<路由器>之外使用<路由>

上诉问题,
解决第一种方式:可以在入口文件index.js中的外层包裹一层容器HashRouter或者BrowserRouter,
修改如下:
src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
// 入口文件引入HashRouter或者BrowserRouter
// import {HashRouter} from 'react-router-dom';
import {BrowserRouter} from 'react-router-dom';
import App from './App';

//index.js入口文件
ReactDOM.render(
  // 最顶层需要容器包着
  // 使用HashRouter或者BrowserRouter包裹都可以,表明路由的类型。
  // 
  //   
  // ,
  <BrowserRouter>
      <App/> 
  </BrowserRouter>,
  document.getElementById('root')
);

或者第二种方式:不在入口文件index.js中修改,
直接在父级组件App.js文件中,给路由外层添加一个容器,如下:

return (
  <div>
     {/* 最外层需要容器包裹路由,表明路由的类型*/}
     <BrowserRouter>
        <Route path="/" component={Index} />
        <Route path="/about" component={About} />
        <Route path="/about/more" component={More}/>
     </BrowserRouter>
  </div> 
 ); 

再次运行后
React路由-react-router-dom安装与使用(一)_第1张图片
看截图虽然控制台没报错,但是总感觉哪里不对劲呢?
我们看浏览器地址栏出现的是localhost:3000/about/more,即本应跳转到详情页的,显示详情页内容。
但是"首页"与"关于我们"的内容也一起显示出来了,这是咋回事?

因为在路由path中,匹配url的方式不是相等,而是以指定的url开头
如上例,三者都是以/开头的,都符合条件,所以导致最后输入详情地址时,三个路由页面内容都会出现。我们假设详情后还有内容,我们要访问它的路由,然而结果是前面路由对应的内容全都出来了,这就很不友好了!如果页面布局内容较多,最后会变成啥样我们也不知道!这该咋办呢?

exact属性
两种匹配模式

  • exact 属性表示路由使用 精确匹配模式
  • 非 exact 模式下 / 匹配所有以 / 开头的路由。类似于模糊匹配,前面的问题就是这种情况导致的!

所以,针对上述问题,我们改为精确匹配模式,如下:

{/* exact精确匹配 在component前加上exact,每一个路由都要加*/}
<Route path="/" exact component={IndexPage} />
<Route path="/about" exact component={AboutPage} />
<Route path="/about/more" exact component={AboutMorePage} /> 

看看运行效果吧
React路由-react-router-dom安装与使用(一)_第2张图片
React路由-react-router-dom安装与使用(一)_第3张图片
React路由-react-router-dom安装与使用(一)_第4张图片
ok,已经精确匹配到url了,即对应的路由跳转到对应的页面。
首页localhost:3000/
关于我们localhost:3000/about
详情localhost:3000/about/more

Link 组件
Link 组件用来处理 a 链接 类似的功能。它会在页面中生成一个 a 标签。
设置需注意

  • react-router-dom 拦截了实际 a 标签的默认动作,
  • 然后根据所有使用的路由模式(Hash 或者 HTML5)来进行处理,改变了 URL,但不会发生请求,
  • 同时根据 Route 中的设置把对应的组件显示在指定的位置

to 属性
Link 组件有一个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="/more">详情</Link>        
        </nav>
    )
}

src/App.js 添加如下

import Nav from './component/nav';

{/* Link组件,只改变url */}
<Nav />    
    
{/* path属性,匹配url 
exact精确匹配 在component前加上exact,每一个路由都要加*/}
<Route path="/" exact component={IndexPage} />
<Route path="/about" exact component={AboutPage} />
<Route path="/about/more" exact component={AboutMorePage} />

React路由-react-router-dom安装与使用(一)_第5张图片
如上,点击不同的链接,切换对应的路由下显示的内容

render属性
如果 Route 使用的是 component 来指定组件,那么就不能使用 props,也就是说无法给组件传参。
别慌!Route有一个render属性来帮忙!

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

src/App.js修改如下

funtion App(){
  <div>
     let [shop,setShop] = useState("烤烟再起");
     return (
        {/* Link组件,只改变url */}
        <Nav />
        
        {/* render传值 */}
        <Route path="/" exact render={()=>{
           // return 你要显示的视图
           return <IndexPage shop={shop} setShop={setShop}/>
        }}/>
       <Route path="/about" exact component={AboutPage} />
       <Route path="/more" exact component={AboutMorePage} />
   </div>
)

view/index.js修改

import React from 'react';
export default function IndexPage(props){
    let {shop,setShop} = props;//父组件传过来的参数
    console.log(shop);

    return (
        <h1><a onClick={()=>{setShop('星星点灯')}} 
              style={{cursor:'pointer'}}>hello
            </a>
           首页
        </h1>
    );
}

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

  • activeClassName属性
    当前 URL 与 NavLink 中的 to 匹配的时候,激活 className
  • activeStyle属性
    当前 URL 与 NavLink 中的 to 匹配的时候,激活 activeStyle 中的样式

src/component/nav.js修改如下:

import React from 'react';
import { NavLink } from 'react-router-dom';

export default function Nav() {
    return (
        <nav>
            {/*有个问题:当点击首页之后,再点击关于或者详情时,
            前面给组件添加的类名属性及样式属性还在,需要在添加的属性前加上exact,
            使用精确匹配,即只有点击谁,谁才添加,不点击就不添加 */}
            <NavLink to="/" exact activeClassName="active-index" 
            activeStyle={{ color: 'red' }}>首页</NavLink>
            <span>|</span>

            <NavLink to="/about" exact activeClassName="active-about" 
            activeStyle={{ color: 'red' }}>关于我们</NavLink>
            <span>|</span>
            
            <NavLink to="/more" exact activeClassName="active-more" 
            activeStyle={{ color: 'red' }}>详情</NavLink>
        </nav>
    )
}

你可能感兴趣的:(React,React路由,HashRouter,BrowserRouter,Route组件,Link组件)