知识总结 React 【路由】

151 阅读4分钟

React路由

react-router-dom

  1. react 的一个插件库。
  2. 专门用来实现一个 SPA 应用。
  3. 基于 react 的项目基本都会用到此库。

老版本

声明式导航

  1. 下载

    yarn add react-router-dom@5
    
  2. 引入路由切换

    由于 react-router-dom 插件对外暴露很多方法,因此推荐按需引入,引入 Link 组件。

    import {Link} from 'react-router-dom'
    <Link to="/about"></Link>
    

    发现报错,查看错因,显示“不允许在 Router 外使用 Link 组件”。 Router 中分两种:

    • 哈希模式:HashRouter
    • 历史模式:BrowserRouter
    import {Link, BrowserRouter} from 'react-router-dom'
    <BrowserRouter>
        <Link to="/about"></Link>
        <Link to="/home"></Link>
    </BrowserRouter>
    
  3. 注册路由(编写路由链接)

    <Route path="/about"></Route>
    

    查看效果,又是一样的错误,需要在外侧包裹 Router,包裹即可。

    <BrowserRouter>
        <Route path="/about" component={About}></Route>
        <Route path="/home" component={Home}></Route>
    </BrowserRouter>
    

    点击后发现路径路由发生改变,但是显示的内容没有变化。这是因为 BrowserRouter 路由器只能用一个路由器去管理,分开写自然没有效果。

    解决方法:在 index.js 里包裹。

    import {BrowserRouter} from 'react-router-dom'
    
    ReactDOM.render(
        <BrowserRouter>
            <App />
        </BrowserRouter>,
        doument.getElementById('root')
    )
    

总结:

  1. 明确好界面中的导航区和显示区
  2. 导航区的a标签改为link标签,to为路径
  3. 显示区写route标签进行路径的匹配,path为路径,component为显示的那个组件
  4. 在入口文件把AppHashRouterBrowserRouter包裹起来

历史模式和哈希模式的区别

  1. 底层原理不同
    • 历史模式使用的是H5的api,不兼容IE9及以下。
    • 哈希模式使用的是url的哈希值。
  2. path表现形式不同
    • 历史模式没有#。
    • 哈希模式有#。
  3. 刷新后对路由state参数的影响
    • 历史模式没有任何影响,因为state保存在history对象内。
    • 哈希模式刷新后数据会丢失!
  4. 备注:哈希模式可以用于解决一些路径错误相关的问题。

组件NavLink

类名高亮

如果有点击组件显示时有高亮的效果,可以使用 NavLink 组件。

工作原理:使用了 NavLink 组件当前被激活时会添加一个 active 类名。这个类名可以通过 activeClassName 来修改。

<NavLink activeClassName="daodao" to="/home" component={Home}>Home</NavLink>

文本内容

在上面的代码中使用的双标签的形式,在里面放置内容。但对于 NavLink 而言有一个属性 children ,也可以设置这个文本内容。

<NavLink activeClassName="daodao" to="/home" component={Home} children={Home} />

效果依旧能够实现。

封装

  • 使用的组件
    <myNavLink children={} to=""></myNavLink>
    
  • 封装的组件
    <NavLink activeClassName="daodao" {...this.props} />
    

组件Switch

看一个案例:

<Route path="/home" component={Home}></Route>
<Route path="/home" component={Test}></Route>

在页面中,当路由路径为 /home 时,会把 HomeTest 两个组件都渲染出来,说明在路由渲染时,他不会一匹配就停止,而是一直查询下去,如果路由很多则很浪费性能。

此时可以用到 Switch 组件,把 Route 包裹起来即可。

<Switch>
    <Route path="/home" component={Home}></Route>
    <Route path="/home" component={Test}></Route>
</Switch>

总结:

  1. 通常情况下,pathcomponent 是一一对应的。
  2. Switch 可以提高路由匹配效率(单一匹配)

严格匹配与模糊匹配

  1. 默认使用模糊匹配,输出的路径必须包含要匹配的路径,且顺序要一致。
  2. 开启严格匹配:<Route exact path="" component={}></Route>
  3. 严格匹配不要随便开启,需要再开,有时候开启会导致无法继续匹配二级路由。

Redirect

放在路由注册的最下方,作用是重定向,当所有路由都无法匹配时,重定向指向一个路由组件显示。

<Switch>
    <Route path="/home" component={Home}></Route>
    <Route path="/home" component={Test}></Route>
    <Redirect to="/about" />
</Switch>

路由嵌套

路由的匹配是按照注册顺序来查找,因此父组件的路由会先查询,查询到了再查询其子路由。因此要在二级路由前添加一级路由的路径。

路由传参

params参数

  1. 路由路径上用 params 携带参数
    <Link to={`/home/${id}`}></Link>
    
  2. 设置动态路由声明接收参数
    <Route path="/home/:id" component={Home}></Route>
    
  3. 子组件通过 this.props.metch.params 拿到想要的数据对象
    const {id} = this.props.metch.params
    

search参数

  1. 路由路径上用 search 传递参数

    <Link to={`/home/?id=${id}&title=${title}`}></Link>
    
  2. search参数不需要声明接收,正常注册路由即可

    <Route path="/home" component={Home}></Route>
    
  3. 子组件通过 this.props.location.search 接收search参数

    拿到的是一个字符串,可以通过一个库来使用。

    import qs from 'qs'
    const {search} = this.props.location
    const res = qs.parse(search) // {?id: "1", title: "xx"} 把问号干掉即可
    const res = qs.parse(search.slice(1)) // {id: "1", title: "xx"}
    

拓展:qs的使用

  • 对象转字符串
    const obj = {name:'dao', age:21}
    console.log(qs.stringiFy(obj)) // name=dao&age=21
    
  • 字符串转对象
    const str = name=dao&age=21
    console.log(qs.parse(str)) // {name:'dao', age:21}
    

state参数

  1. 传递state参数
    <Link to={{pathname:'/home', state:{id:id}}}></Link>
    
  2. state参数不需要声明接收,正常注册路由即可
    <Route path="/home" component={Home}></Route>
    
  3. 子组件通过 this.props.location.state 接收state参数
    const {id} = this.props.location.state || {}
    

注意:

这种方法地址栏上没有数据路径,刷新之后数据也不会丢失。因为使用了 BrowserRouter 模式的路由,会一直维护 history 对象里的数据。而 location 对象包括在 history 内。

总结

  1. 实在要说,params使用的更多,state用于参数保密的情况。
  2. state方法需要额外携带state对象,因此to写成对象形式,其余不需要这么麻烦

编程式导航

params参数

replaceShow = (id) => {
    this.props.history.replace(`/home/${id}`)
}

search参数

replaceShow = (id) => {
    this.props.history.replace(`/home/?id=${id}`)
}

state参数

replaceShow = (id) => {
    this.props.history.replace(`/home`, {id})
}

前进后退

  1. 前进
    forword = () => {
        this.props.history.goForword()
    }
    
  2. 后退
    back = () => {
        this.props.history.goBack()
    }
    
  3. 指定跳转的页数,括号内填入数值,正数为前进,负数为后退
    go = () => {
        this.props.history.go(n)
    }
    

路由组件与一般组件

区别

  1. 写法不同:一般组件直接引入,写组件标签即可。路由组件引入,通过 Route 组件注册使用。
  2. 存放文件夹不同:路由组件放在 pages 文件夹,一般组件放在 component 文件夹。
  3. 接收到的 props 不同:一般组件写标签时传递啥就接受到啥;路由组件固定接收三个对象:historylocationmatch

withRouter

路由组件的 this.props 才有 history api对象,一般组件拿不到,如果一般组件想要使用路由的前进后退,可以使用 withRouter 函数。

class Header extends Component {
    back = () => {
       this.props.history.goBack()
    }
}

export default withRouter(Header)

在导出组件时使用 withRouter 函数包裹组件,可以加工一般组件,让一般组件具备路由组件所拥有的属性。

withRouter 的返回值是一个新租件。

新版本

  1. 下载
    yarn add react-router-dom