React基础(三)


路由

React中可以使用react-router-dom来实现前端路由功能。它使用分别暴露暴露出一些组件以供我们使用。

常用的内置路由组件有:

  • 用 BrowserRouter 标签包裹整个页面,使页面有一个全局的管理路由关系的路由器。并将路由的模式设置为常规路由模式,类似于 Vue 中 history 模式

  • HashRouter 标签和 BrowserRouter 一样,只是路由模式变更为 hash 模式

  • Route 标签是控制路由组件的显示和隐藏,并且可以使用exact={true}将路由匹配模式设置为精准匹配,而不是默认的模糊匹配。若该路由下还有子路由,则不能使用精准匹配模式

  • Redirect 标签是设置一个默认的重定向路由,我们可以使用它设定默认路由。当所有路由匹配失败时,也会重定向到该路由

  • Link 标签是用于更改地址栏的路径,当我们点击该标签时地址栏的路径就会变成该标签的路径

  • NavLink 标签能够设定导航的默认样式,利用activeClassName="指定样式类"可以将导航标签的样式设置为指定的类的样式

  • Switch 标签的功能是将原本路由的全匹配模式改为匹配完即终止,默认当匹配到多个 Route 标签时会将所有的匹配到的路由组件展示,使用 Switch 包裹则当匹配到第一 Route 时即停止往下匹配

例如我们要实现一个页面的路由切换,那你能利用<Link><Route>组件将路由组件和跳转标签关联起来。

// index.jsx
// 使用history模式路由
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {BrowserRouter} from 'react-router-dom'

ReactDOM.render(
	<BrowserRouter>
		<App/>
	</BrowserRouter>,
document.getElementById('root'))
// app.jsx
// 需求:点击标签跳转到about页面,并启用replace模式和精准匹配
// 		设置默认页面为404
//		设置初次匹配到即停止
import React, { Component } from 'react'
import Home from './components/Home'
import About from './components/About'
import DefaultPage from './components/404'
import {NavLink,Route,Redirect,Switch} from 'react-router-dom'

export default class App extends Component {
	render(){
        return (
            <div>
                <ul>
                    <li>
                        <NavLink to="/about" activeClassName="demo" replace={true}>AboutPage</NavLink>
                        <NavLink to="/home" activeClassName="demo">HomePage</NavLink>
                    </li>
                </ul>
                <div>
                    <Switch>
                        <Route path="/about" exact={true}></Route>
                        <Route path="/home"></Route>
                        <Redirect to="/about">
                    </Switch>
                </div>
              </div>
        )
    }
}

路由传参

有时候我们想在路由跳转的时候携带一些参数给对应的路由组件,路由组件可以根据传递过来的参数发送网络请求。在React当中有总共有三种路由传参的方式,分别是:

  • params 传参
  • search 传参
  • state 传参

params 传参

params传参就是利用地址栏里的params参数进行参数的传递,例如组件 A 给组件 B 传递两个 params 参数idname

// A.jsx
import React,{Component} from 'react'
import {Link,Route,Router} from 'react-router-dom'
import B from "./B.jsx"

export default class A extends Component {
    state = {
        id:"001",
        name:"asuhe"
    }
    render(){
        return (
            <div>
                <div>
                    <Link to={`/b/${this.state.id}/${this.state.name}`}>click</Link>
                </div>
                <div>
                    {/* react-router-dom v6版本以下写法 */}
                    {/* <Route path="/b/:id/:name" component={B} /> */}
                    <Routes>
                        <Route path="/b/:id/:name" element={<B></B>} />
                    </Routes>
                </div>
            </div>
        )
    }
}

而在组件 B 中,我们可以在 props 中接收到多个属性对象,传入的 params 参数我们可以在组件 B 的 props 对象中的 match 里的 params 中获取。

// B.jsx
import React,{Component} from "react"
export default class B extends Component {
    render(){
        console.log(this.props)
    }
}

react-router-dom v5.x

//路由链接(携带参数):
<Link to='/demo/test/tom/18'}>详情</Link>
//或 <Link to={{ pathname:'/demo/test/tom/18' }}>详情</Link>

//注册路由(声明接收):
<Route path="/demo/test/:name/:age" component={Test}/>

//接收参数:
this.props.match.params

react-router-dom v6.x

//路由链接(携带参数):
<Link to={{ pathname:`/b/child1/${id}/${title}` }}>Child1</Link>
//或 <Link  to={`/b/child1/${id}/${title}`}>Child1</Link>

//注册路由(声明接收):
<Route path="/b/child1/:id/:title" component={Test}/>

//接收参数:
import { useParams } from "react-router-dom";
const params = useParams();
//params参数 => {id: "01", title: "消息1"}

search 传参

React中的search传参实际上就是我们传统请求参数中的query传参。只是写法稍微有些差异。

// A.jsx
render(){
    return(
        <div>
            <div>
                <Link to={`/b?id=${this.state.id}&$name={this.state.name}`}>点击跳转至组件B</Link>
            </div>
            <div>
                <Router>
                    <Route path="/b" component={B}></Route>
                </Router>
            </div>
        </div>
    )
}

传入的 search 参数我们可以在组件 B 的 props 对象中的 location 里的 search 中获取。

react-router-dom v5.x

//路由链接(携带参数):
<Link to='/demo/test?name=tom&age=18'}>详情</Link>

//注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/>

//接收参数:
this.props.location.search

//备注:获取到的search是urlencoded编码字符串(例如: ?id=10&name=zhangsan),需要借助query-string解析参数成对象

react-router-dom v6.x

//路由链接(携带参数):
 <Link className="nav" to={`/b/child2?age=20&name=zhangsan`}>Child2</Link>

//注册路由(无需声明,正常注册即可):
<Route path="/b/child2" component={Test}/>

//接收参数方法1:
import { useLocation } from "react-router-dom";
import qs from "query-string";
const { search } = useLocation();
//search参数 => {age: "20", name: "zhangsan"}

//接收参数方法2:
import { useSearchParams } from "react-router-dom";
const [searchParams, setSearchParams] = useSearchParams();
// console.log( searchParams.get("id")); // 12

//备注:获取到的search是urlencoded编码字符串(例如: ?age=20&name=zhangsan),需要借助query-string解析参数成对象

state 传参

state传参就是把<Link>里面的to属性换成一个对象,再将路径和参数信息填入该对象。

// A.jsx
render(){
    <div>
        <div>
            <Link to={{pathname:"/b",state:{id:this.state.id,name:this.state.name}}}>点击跳转至组件B</Link>
        </div>
        <div>
            <Router>
                <Route path="/b" component={B}></Route>
            </Router>
        </div>
    </div>
    )
}

传入的 state 参数我们可以在组件 B 的 props 对象中的 location 里的 state 中获取。

react-router-dom v5.x

//路由链接(携带参数):
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>

//注册路由(无需声明,正常注册即可):
 <Route path="/demo/test" component={Test}/>

//接收参数:
this.props.location.state

//备注:刷新也可以保留住参数

react-router-dom v6.x

//通过Link的state属性传递参数
 <Link
     className="nav"
     to={`/b/child2`}
     state={{ id: 999, name: "i love merlin" }}
 >
    Child2
</Link>

//注册路由(无需声明,正常注册即可):
<Route path="/b/child2" component={Test}/>

//接收参数:
import { useLocation } from "react-router-dom";
const { state } = useLocation();
//state参数 => {id: 999, name: "我是asuhe"}

//备注:刷新也可以保留住参数

编程式路由

编程式路由可以允许我们用javascript动态生成路由链接

react-router-dom v5.x

// A.jsx
class A extends Component {
    pushRoute = ()=>{
        this.props.history.push("/b")
    }
    render(){
        return (
            <div>
                <button onClick={this.pushRoute}></button>
                <Route path="/b" component={B}/>
            </div>

        )
    }
}

react-router-dom v6.x

function A {
    const navigate = useNavigate()
    navigate('b', {
        state: {
            id: item.id,
            content: item.content,
            title: item.title
        }
    })
    return (
    	<div>
            <button onClick={() => navigate(-1)}>back</button>
            <button onClick={() => navigate(1)}>go</button>
        </div>
    )
}

withRouter

当我想要在非路由组件中使用路由组件中的pushreplace等编程式路由的函数时,就可以使用withRouter来获取这些函数。withRouter作为一个高阶组件,其作用是将一个组件包裹进Route里面, 然后react-router的三个对象history,、location、match就会被放进这个组件的 props 属性中。

import React, { Component } from 'react'
import {withRouter} from 'react-router-dom'
class C extends Component {
	back = ()=>{
		this.props.history.goBack()
	}
  	forward =  ()=>{
		this.props.history.goForward()
	}
	render() {
		return (
			<div >
                <button onClick={this.back}>回退</button>
                <button onClick={this.forward}>前进</button>
			</div>
		)
	}
}
export default withRouter(C)